From patchwork Fri Mar 11 14:34:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778109 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7868DC433EF for ; Fri, 11 Mar 2022 14:35:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349407AbiCKOg7 (ORCPT ); Fri, 11 Mar 2022 09:36:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58426 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S245379AbiCKOg6 (ORCPT ); Fri, 11 Mar 2022 09:36:58 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AD4901C8D96; Fri, 11 Mar 2022 06:35:54 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id ED40E240015; Fri, 11 Mar 2022 14:35:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009353; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=vD0F7ErVbg0idhLXtMNeE7PtA2hj3UWkov1fDa4SQJs=; b=pIJ8Xdq04Pr8kyby8OHM+/X8VdIwjEFxjiHH8ozicaEMWZ3MaNidatNyh15vRxkRM7SK2V gbmQzRMhb4mG2YWLeePp7qkV6ZAG8O/rEFHyFQxxkv9GxNlaGZoco/9pOCAc6yjKSAcjlJ XN2vDPV5sAbUbuiqAEqXe4gM3RX1W3YkXXrjzpD7ZzDOvcAH/ryHjWLBkww/lbTbGKoyLw hUOq3GbmtIHCGfkLpHTwn9EJgDG+XUx8tlvyUh3z1QnuCgUl0obN3nhuoKQWe1djpNxVel pIltTcZeWA/W8cMk1+/HMgFEuvIcdWIpqn+xzZbeL8uxDGd43xaMHohtX/0AiA== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni , Maxime Ripard Subject: [PATCH v3 01/46] media: sun6i-csi: Define and use driver name and (reworked) description Date: Fri, 11 Mar 2022 15:34:47 +0100 Message-Id: <20220311143532.265091-2-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Add proper defines for driver name and description instead of MODULE_NAME and hardcoding (cosmetics). Also rework the description while at it to mention the hardware generation that the driver supports and remove the video capture mentions since it applies to the whole media device. Signed-off-by: Paul Kocialkowski Reviewed-by: Maxime Ripard --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 14 ++++++-------- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h | 3 +++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index fc96921b0583..43dcd8117d3f 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -27,8 +27,6 @@ #include "sun6i_csi.h" #include "sun6i_csi_reg.h" -#define MODULE_NAME "sun6i-csi" - struct sun6i_csi_dev { struct sun6i_csi csi; struct device *dev; @@ -730,7 +728,7 @@ static int sun6i_csi_v4l2_init(struct sun6i_csi *csi) int ret; csi->media_dev.dev = csi->dev; - strscpy(csi->media_dev.model, "Allwinner Video Capture Device", + strscpy(csi->media_dev.model, SUN6I_CSI_DESCRIPTION, sizeof(csi->media_dev.model)); csi->media_dev.hw_revision = 0; snprintf(csi->media_dev.bus_info, sizeof(csi->media_dev.bus_info), @@ -755,7 +753,7 @@ static int sun6i_csi_v4l2_init(struct sun6i_csi *csi) goto free_ctrl; } - ret = sun6i_video_init(&csi->video, csi, "sun6i-csi"); + ret = sun6i_video_init(&csi->video, csi, SUN6I_CSI_NAME); if (ret) goto unreg_v4l2; @@ -870,8 +868,8 @@ static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev, if (irq < 0) return -ENXIO; - ret = devm_request_irq(&pdev->dev, irq, sun6i_csi_isr, 0, MODULE_NAME, - sdev); + ret = devm_request_irq(&pdev->dev, irq, sun6i_csi_isr, 0, + SUN6I_CSI_NAME, sdev); if (ret) { dev_err(&pdev->dev, "Cannot request csi IRQ\n"); return ret; @@ -924,12 +922,12 @@ static struct platform_driver sun6i_csi_platform_driver = { .probe = sun6i_csi_probe, .remove = sun6i_csi_remove, .driver = { - .name = MODULE_NAME, + .name = SUN6I_CSI_NAME, .of_match_table = of_match_ptr(sun6i_csi_of_match), }, }; module_platform_driver(sun6i_csi_platform_driver); -MODULE_DESCRIPTION("Allwinner V3s Camera Sensor Interface driver"); +MODULE_DESCRIPTION("Allwinner A31 Camera Sensor Interface driver"); MODULE_AUTHOR("Yong Deng "); MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 3a38d107ae3f..e04f3c3fa27b 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -14,6 +14,9 @@ #include "sun6i_video.h" +#define SUN6I_CSI_NAME "sun6i-csi" +#define SUN6I_CSI_DESCRIPTION "Allwinner A31 CSI Device" + struct sun6i_csi; /** From patchwork Fri Mar 11 14:34:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778113 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 72908C433F5 for ; Fri, 11 Mar 2022 14:36:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349430AbiCKOhG (ORCPT ); Fri, 11 Mar 2022 09:37:06 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58500 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349414AbiCKOhC (ORCPT ); Fri, 11 Mar 2022 09:37:02 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9EDE11C8D93; Fri, 11 Mar 2022 06:35:56 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 56CD424000C; Fri, 11 Mar 2022 14:35:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009355; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=JzRrrmeAX+LabyswBUsKXf/jbz9R/54V91EJ/+peMhE=; b=Oa47l7JPpKREVWkcS9k/7G4eZ2i8jVGnbC9I8aEWAvI98iC8nQ2j+IBhRi+FnpcHwe69qX Sti4Dp/ro3On0mHrUHT8Uby+sTE1kVKGQkJ8NtuxX3M2bCrPC5PmB5yDhxc9fYr6kuX4Vk RWazbrIUbhFGRe5kiGT+SIBY1ZYCDNMBvF53rfrMQ1sVU79/50JzgLkqYkyWmRAcK4cRAk P9svzxZpg0IAurCdKa1zY56hCDb2Oy/fFGvnB4Ufi5UcFdyLpURF/szVwsNNtPTK1I1yHC J0TC+4UnP/0VTlm87l38RU7KC/L5bdygEXEyT2Ju5y8QZHBuxf7UHQHb+uiZWw== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni , Maxime Ripard Subject: [PATCH v3 02/46] media: sun6i-csi: Refactor main driver data structures Date: Fri, 11 Mar 2022 15:34:48 +0100 Message-Id: <20220311143532.265091-3-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Merge contents of structs sun6i_csi and sun6i_csi_dev into a main sun6i_csi_device structure holding a sun6i_csi_v4l2 struct for things related to v4l2, as well as the already-existing sun6i_csi_video and sun6i_csi_config which are left unchanged. This mostly simplifies accessing stuff by having a single main structure accessible to every part of the code instead of a private definition. No functional change is intended in this commit, variables are just moved around (cosmetics). Signed-off-by: Paul Kocialkowski Reviewed-by: Maxime Ripard --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 351 +++++++++--------- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 34 +- .../platform/sunxi/sun6i-csi/sun6i_video.c | 52 +-- .../platform/sunxi/sun6i-csi/sun6i_video.h | 8 +- 4 files changed, 221 insertions(+), 224 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 43dcd8117d3f..5fbaa1e99412 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -27,37 +27,20 @@ #include "sun6i_csi.h" #include "sun6i_csi_reg.h" -struct sun6i_csi_dev { - struct sun6i_csi csi; - struct device *dev; - - struct regmap *regmap; - struct clk *clk_mod; - struct clk *clk_ram; - struct reset_control *rstc_bus; - - int planar_offset[3]; -}; - -static inline struct sun6i_csi_dev *sun6i_csi_to_dev(struct sun6i_csi *csi) -{ - return container_of(csi, struct sun6i_csi_dev, csi); -} - /* TODO add 10&12 bit YUV, RGB support */ -bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, +bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev, u32 pixformat, u32 mbus_code) { - struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi); + struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; /* * Some video receivers have the ability to be compatible with * 8bit and 16bit bus width. * Identify the media bus format from device tree. */ - if ((sdev->csi.v4l2_ep.bus_type == V4L2_MBUS_PARALLEL - || sdev->csi.v4l2_ep.bus_type == V4L2_MBUS_BT656) - && sdev->csi.v4l2_ep.bus.parallel.bus_width == 16) { + if ((v4l2->v4l2_ep.bus_type == V4L2_MBUS_PARALLEL + || v4l2->v4l2_ep.bus_type == V4L2_MBUS_BT656) + && v4l2->v4l2_ep.bus.parallel.bus_width == 16) { switch (pixformat) { case V4L2_PIX_FMT_NV12_16L16: case V4L2_PIX_FMT_NV12: @@ -74,13 +57,14 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, case MEDIA_BUS_FMT_YVYU8_1X16: return true; default: - dev_dbg(sdev->dev, "Unsupported mbus code: 0x%x\n", + dev_dbg(csi_dev->dev, + "Unsupported mbus code: 0x%x\n", mbus_code); break; } break; default: - dev_dbg(sdev->dev, "Unsupported pixformat: 0x%x\n", + dev_dbg(csi_dev->dev, "Unsupported pixformat: 0x%x\n", pixformat); break; } @@ -137,7 +121,7 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, case MEDIA_BUS_FMT_YVYU8_2X8: return true; default: - dev_dbg(sdev->dev, "Unsupported mbus code: 0x%x\n", + dev_dbg(csi_dev->dev, "Unsupported mbus code: 0x%x\n", mbus_code); break; } @@ -152,50 +136,50 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, return (mbus_code == MEDIA_BUS_FMT_JPEG_1X8); default: - dev_dbg(sdev->dev, "Unsupported pixformat: 0x%x\n", pixformat); + dev_dbg(csi_dev->dev, "Unsupported pixformat: 0x%x\n", + pixformat); break; } return false; } -int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable) +int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) { - struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi); - struct device *dev = sdev->dev; - struct regmap *regmap = sdev->regmap; + struct device *dev = csi_dev->dev; + struct regmap *regmap = csi_dev->regmap; int ret; if (!enable) { regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0); - clk_disable_unprepare(sdev->clk_ram); + clk_disable_unprepare(csi_dev->clk_ram); if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clk_rate_exclusive_put(sdev->clk_mod); - clk_disable_unprepare(sdev->clk_mod); - reset_control_assert(sdev->rstc_bus); + clk_rate_exclusive_put(csi_dev->clk_mod); + clk_disable_unprepare(csi_dev->clk_mod); + reset_control_assert(csi_dev->reset); return 0; } - ret = clk_prepare_enable(sdev->clk_mod); + ret = clk_prepare_enable(csi_dev->clk_mod); if (ret) { - dev_err(sdev->dev, "Enable csi clk err %d\n", ret); + dev_err(csi_dev->dev, "Enable csi clk err %d\n", ret); return ret; } if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clk_set_rate_exclusive(sdev->clk_mod, 300000000); + clk_set_rate_exclusive(csi_dev->clk_mod, 300000000); - ret = clk_prepare_enable(sdev->clk_ram); + ret = clk_prepare_enable(csi_dev->clk_ram); if (ret) { - dev_err(sdev->dev, "Enable clk_dram_csi clk err %d\n", ret); + dev_err(csi_dev->dev, "Enable clk_dram_csi clk err %d\n", ret); goto clk_mod_disable; } - ret = reset_control_deassert(sdev->rstc_bus); + ret = reset_control_deassert(csi_dev->reset); if (ret) { - dev_err(sdev->dev, "reset err %d\n", ret); + dev_err(csi_dev->dev, "reset err %d\n", ret); goto clk_ram_disable; } @@ -204,15 +188,15 @@ int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable) return 0; clk_ram_disable: - clk_disable_unprepare(sdev->clk_ram); + clk_disable_unprepare(csi_dev->clk_ram); clk_mod_disable: if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clk_rate_exclusive_put(sdev->clk_mod); - clk_disable_unprepare(sdev->clk_mod); + clk_rate_exclusive_put(csi_dev->clk_mod); + clk_disable_unprepare(csi_dev->clk_mod); return ret; } -static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_dev *sdev, +static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_device *csi_dev, u32 mbus_code, u32 pixformat) { /* non-YUV */ @@ -230,12 +214,13 @@ static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_dev *sdev, } /* not support YUV420 input format yet */ - dev_dbg(sdev->dev, "Select YUV422 as default input format of CSI.\n"); + dev_dbg(csi_dev->dev, "Select YUV422 as default input format of CSI.\n"); return CSI_INPUT_FORMAT_YUV422; } -static enum csi_output_fmt get_csi_output_format(struct sun6i_csi_dev *sdev, - u32 pixformat, u32 field) +static enum csi_output_fmt +get_csi_output_format(struct sun6i_csi_device *csi_dev, u32 pixformat, + u32 field) { bool buf_interlaced = false; @@ -294,14 +279,14 @@ static enum csi_output_fmt get_csi_output_format(struct sun6i_csi_dev *sdev, return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8; default: - dev_warn(sdev->dev, "Unsupported pixformat: 0x%x\n", pixformat); + dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x\n", pixformat); break; } return CSI_FIELD_RAW_8; } -static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, +static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_device *csi_dev, u32 mbus_code, u32 pixformat) { /* Input sequence does not apply to non-YUV formats */ @@ -328,7 +313,7 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, case MEDIA_BUS_FMT_YVYU8_2X8: return CSI_INPUT_SEQ_YVYU; default: - dev_warn(sdev->dev, "Unsupported mbus code: 0x%x\n", + dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n", mbus_code); break; } @@ -350,7 +335,7 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, case MEDIA_BUS_FMT_YVYU8_2X8: return CSI_INPUT_SEQ_YUYV; default: - dev_warn(sdev->dev, "Unsupported mbus code: 0x%x\n", + dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n", mbus_code); break; } @@ -360,7 +345,7 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, return CSI_INPUT_SEQ_YUYV; default: - dev_warn(sdev->dev, "Unsupported pixformat: 0x%x, defaulting to YUYV\n", + dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x, defaulting to YUYV\n", pixformat); break; } @@ -368,23 +353,23 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, return CSI_INPUT_SEQ_YUYV; } -static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev) +static void sun6i_csi_setup_bus(struct sun6i_csi_device *csi_dev) { - struct v4l2_fwnode_endpoint *endpoint = &sdev->csi.v4l2_ep; - struct sun6i_csi *csi = &sdev->csi; + struct v4l2_fwnode_endpoint *endpoint = &csi_dev->v4l2.v4l2_ep; + struct sun6i_csi_config *config = &csi_dev->config; unsigned char bus_width; u32 flags; u32 cfg; bool input_interlaced = false; - if (csi->config.field == V4L2_FIELD_INTERLACED - || csi->config.field == V4L2_FIELD_INTERLACED_TB - || csi->config.field == V4L2_FIELD_INTERLACED_BT) + if (config->field == V4L2_FIELD_INTERLACED + || config->field == V4L2_FIELD_INTERLACED_TB + || config->field == V4L2_FIELD_INTERLACED_BT) input_interlaced = true; bus_width = endpoint->bus.parallel.bus_width; - regmap_read(sdev->regmap, CSI_IF_CFG_REG, &cfg); + regmap_read(csi_dev->regmap, CSI_IF_CFG_REG, &cfg); cfg &= ~(CSI_IF_CFG_CSI_IF_MASK | CSI_IF_CFG_MIPI_IF_MASK | CSI_IF_CFG_IF_DATA_WIDTH_MASK | @@ -432,7 +417,7 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev) cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE; break; default: - dev_warn(sdev->dev, "Unsupported bus type: %d\n", + dev_warn(csi_dev->dev, "Unsupported bus type: %d\n", endpoint->bus_type); break; } @@ -450,54 +435,54 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev) case 16: /* No need to configure DATA_WIDTH for 16bit */ break; default: - dev_warn(sdev->dev, "Unsupported bus width: %u\n", bus_width); + dev_warn(csi_dev->dev, "Unsupported bus width: %u\n", bus_width); break; } - regmap_write(sdev->regmap, CSI_IF_CFG_REG, cfg); + regmap_write(csi_dev->regmap, CSI_IF_CFG_REG, cfg); } -static void sun6i_csi_set_format(struct sun6i_csi_dev *sdev) +static void sun6i_csi_set_format(struct sun6i_csi_device *csi_dev) { - struct sun6i_csi *csi = &sdev->csi; + struct sun6i_csi_config *config = &csi_dev->config; u32 cfg; u32 val; - regmap_read(sdev->regmap, CSI_CH_CFG_REG, &cfg); + regmap_read(csi_dev->regmap, CSI_CH_CFG_REG, &cfg); cfg &= ~(CSI_CH_CFG_INPUT_FMT_MASK | CSI_CH_CFG_OUTPUT_FMT_MASK | CSI_CH_CFG_VFLIP_EN | CSI_CH_CFG_HFLIP_EN | CSI_CH_CFG_FIELD_SEL_MASK | CSI_CH_CFG_INPUT_SEQ_MASK); - val = get_csi_input_format(sdev, csi->config.code, - csi->config.pixelformat); + val = get_csi_input_format(csi_dev, config->code, + config->pixelformat); cfg |= CSI_CH_CFG_INPUT_FMT(val); - val = get_csi_output_format(sdev, csi->config.pixelformat, - csi->config.field); + val = get_csi_output_format(csi_dev, config->pixelformat, + config->field); cfg |= CSI_CH_CFG_OUTPUT_FMT(val); - val = get_csi_input_seq(sdev, csi->config.code, - csi->config.pixelformat); + val = get_csi_input_seq(csi_dev, config->code, + config->pixelformat); cfg |= CSI_CH_CFG_INPUT_SEQ(val); - if (csi->config.field == V4L2_FIELD_TOP) + if (config->field == V4L2_FIELD_TOP) cfg |= CSI_CH_CFG_FIELD_SEL_FIELD0; - else if (csi->config.field == V4L2_FIELD_BOTTOM) + else if (config->field == V4L2_FIELD_BOTTOM) cfg |= CSI_CH_CFG_FIELD_SEL_FIELD1; else cfg |= CSI_CH_CFG_FIELD_SEL_BOTH; - regmap_write(sdev->regmap, CSI_CH_CFG_REG, cfg); + regmap_write(csi_dev->regmap, CSI_CH_CFG_REG, cfg); } -static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev) +static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev) { - struct sun6i_csi_config *config = &sdev->csi.config; + struct sun6i_csi_config *config = &csi_dev->config; u32 bytesperline_y; u32 bytesperline_c; - int *planar_offset = sdev->planar_offset; + int *planar_offset = csi_dev->planar_offset; u32 width = config->width; u32 height = config->height; u32 hor_len = width; @@ -507,7 +492,7 @@ static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev) case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_VYUY: - dev_dbg(sdev->dev, + dev_dbg(csi_dev->dev, "Horizontal length should be 2 times of width for packed YUV formats!\n"); hor_len = width * 2; break; @@ -515,10 +500,10 @@ static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev) break; } - regmap_write(sdev->regmap, CSI_CH_HSIZE_REG, + regmap_write(csi_dev->regmap, CSI_CH_HSIZE_REG, CSI_CH_HSIZE_HOR_LEN(hor_len) | CSI_CH_HSIZE_HOR_START(0)); - regmap_write(sdev->regmap, CSI_CH_VSIZE_REG, + regmap_write(csi_dev->regmap, CSI_CH_VSIZE_REG, CSI_CH_VSIZE_VER_LEN(height) | CSI_CH_VSIZE_VER_START(0)); @@ -550,7 +535,7 @@ static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev) bytesperline_c * height; break; default: /* raw */ - dev_dbg(sdev->dev, + dev_dbg(csi_dev->dev, "Calculating pixelformat(0x%x)'s bytesperline as a packed format\n", config->pixelformat); bytesperline_y = (sun6i_csi_get_bpp(config->pixelformat) * @@ -561,46 +546,42 @@ static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev) break; } - regmap_write(sdev->regmap, CSI_CH_BUF_LEN_REG, + regmap_write(csi_dev->regmap, CSI_CH_BUF_LEN_REG, CSI_CH_BUF_LEN_BUF_LEN_C(bytesperline_c) | CSI_CH_BUF_LEN_BUF_LEN_Y(bytesperline_y)); } -int sun6i_csi_update_config(struct sun6i_csi *csi, +int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev, struct sun6i_csi_config *config) { - struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi); - if (!config) return -EINVAL; - memcpy(&csi->config, config, sizeof(csi->config)); + memcpy(&csi_dev->config, config, sizeof(csi_dev->config)); - sun6i_csi_setup_bus(sdev); - sun6i_csi_set_format(sdev); - sun6i_csi_set_window(sdev); + sun6i_csi_setup_bus(csi_dev); + sun6i_csi_set_format(csi_dev); + sun6i_csi_set_window(csi_dev); return 0; } -void sun6i_csi_update_buf_addr(struct sun6i_csi *csi, dma_addr_t addr) +void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev, + dma_addr_t addr) { - struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi); - - regmap_write(sdev->regmap, CSI_CH_F0_BUFA_REG, - (addr + sdev->planar_offset[0]) >> 2); - if (sdev->planar_offset[1] != -1) - regmap_write(sdev->regmap, CSI_CH_F1_BUFA_REG, - (addr + sdev->planar_offset[1]) >> 2); - if (sdev->planar_offset[2] != -1) - regmap_write(sdev->regmap, CSI_CH_F2_BUFA_REG, - (addr + sdev->planar_offset[2]) >> 2); + regmap_write(csi_dev->regmap, CSI_CH_F0_BUFA_REG, + (addr + csi_dev->planar_offset[0]) >> 2); + if (csi_dev->planar_offset[1] != -1) + regmap_write(csi_dev->regmap, CSI_CH_F1_BUFA_REG, + (addr + csi_dev->planar_offset[1]) >> 2); + if (csi_dev->planar_offset[2] != -1) + regmap_write(csi_dev->regmap, CSI_CH_F2_BUFA_REG, + (addr + csi_dev->planar_offset[2]) >> 2); } -void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable) +void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable) { - struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi); - struct regmap *regmap = sdev->regmap; + struct regmap *regmap = csi_dev->regmap; if (!enable) { regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON, 0); @@ -624,7 +605,7 @@ void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable) /* ----------------------------------------------------------------------------- * Media Controller and V4L2 */ -static int sun6i_csi_link_entity(struct sun6i_csi *csi, +static int sun6i_csi_link_entity(struct sun6i_csi_device *csi_dev, struct media_entity *entity, struct fwnode_handle *fwnode) { @@ -635,24 +616,25 @@ static int sun6i_csi_link_entity(struct sun6i_csi *csi, ret = media_entity_get_fwnode_pad(entity, fwnode, MEDIA_PAD_FL_SOURCE); if (ret < 0) { - dev_err(csi->dev, "%s: no source pad in external entity %s\n", - __func__, entity->name); + dev_err(csi_dev->dev, + "%s: no source pad in external entity %s\n", __func__, + entity->name); return -EINVAL; } src_pad_index = ret; - sink = &csi->video.vdev.entity; - sink_pad = &csi->video.pad; + sink = &csi_dev->video.vdev.entity; + sink_pad = &csi_dev->video.pad; - dev_dbg(csi->dev, "creating %s:%u -> %s:%u link\n", + dev_dbg(csi_dev->dev, "creating %s:%u -> %s:%u link\n", entity->name, src_pad_index, sink->name, sink_pad->index); ret = media_create_pad_link(entity, src_pad_index, sink, sink_pad->index, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); if (ret < 0) { - dev_err(csi->dev, "failed to create %s:%u -> %s:%u link\n", + dev_err(csi_dev->dev, "failed to create %s:%u -> %s:%u link\n", entity->name, src_pad_index, sink->name, sink_pad->index); return ret; @@ -663,27 +645,29 @@ static int sun6i_csi_link_entity(struct sun6i_csi *csi, static int sun6i_subdev_notify_complete(struct v4l2_async_notifier *notifier) { - struct sun6i_csi *csi = container_of(notifier, struct sun6i_csi, - notifier); - struct v4l2_device *v4l2_dev = &csi->v4l2_dev; + struct sun6i_csi_device *csi_dev = + container_of(notifier, struct sun6i_csi_device, + v4l2.notifier); + struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; + struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev; struct v4l2_subdev *sd; int ret; - dev_dbg(csi->dev, "notify complete, all subdevs registered\n"); + dev_dbg(csi_dev->dev, "notify complete, all subdevs registered\n"); sd = list_first_entry(&v4l2_dev->subdevs, struct v4l2_subdev, list); if (!sd) return -EINVAL; - ret = sun6i_csi_link_entity(csi, &sd->entity, sd->fwnode); + ret = sun6i_csi_link_entity(csi_dev, &sd->entity, sd->fwnode); if (ret < 0) return ret; - ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev); + ret = v4l2_device_register_subdev_nodes(v4l2_dev); if (ret < 0) return ret; - return media_device_register(&csi->media_dev); + return media_device_register(&v4l2->media_dev); } static const struct v4l2_async_notifier_operations sun6i_csi_async_ops = { @@ -694,7 +678,7 @@ static int sun6i_csi_fwnode_parse(struct device *dev, struct v4l2_fwnode_endpoint *vep, struct v4l2_async_subdev *asd) { - struct sun6i_csi *csi = dev_get_drvdata(dev); + struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); if (vep->base.port || vep->base.id) { dev_warn(dev, "Only support a single port with one endpoint\n"); @@ -704,7 +688,7 @@ static int sun6i_csi_fwnode_parse(struct device *dev, switch (vep->bus_type) { case V4L2_MBUS_PARALLEL: case V4L2_MBUS_BT656: - csi->v4l2_ep = *vep; + csi_dev->v4l2.v4l2_ep = *vep; return 0; default: dev_err(dev, "Unsupported media bus type\n"); @@ -712,78 +696,82 @@ static int sun6i_csi_fwnode_parse(struct device *dev, } } -static void sun6i_csi_v4l2_cleanup(struct sun6i_csi *csi) +static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev) { - media_device_unregister(&csi->media_dev); - v4l2_async_nf_unregister(&csi->notifier); - v4l2_async_nf_cleanup(&csi->notifier); - sun6i_video_cleanup(&csi->video); - v4l2_device_unregister(&csi->v4l2_dev); - v4l2_ctrl_handler_free(&csi->ctrl_handler); - media_device_cleanup(&csi->media_dev); + struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; + + media_device_unregister(&v4l2->media_dev); + v4l2_async_nf_unregister(&v4l2->notifier); + v4l2_async_nf_cleanup(&v4l2->notifier); + sun6i_video_cleanup(&csi_dev->video); + v4l2_device_unregister(&v4l2->v4l2_dev); + v4l2_ctrl_handler_free(&v4l2->ctrl_handler); + media_device_cleanup(&v4l2->media_dev); } -static int sun6i_csi_v4l2_init(struct sun6i_csi *csi) +static int sun6i_csi_v4l2_init(struct sun6i_csi_device *csi_dev) { + struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; int ret; - csi->media_dev.dev = csi->dev; - strscpy(csi->media_dev.model, SUN6I_CSI_DESCRIPTION, - sizeof(csi->media_dev.model)); - csi->media_dev.hw_revision = 0; - snprintf(csi->media_dev.bus_info, sizeof(csi->media_dev.bus_info), - "platform:%s", dev_name(csi->dev)); + v4l2->media_dev.dev = csi_dev->dev; + strscpy(v4l2->media_dev.model, SUN6I_CSI_DESCRIPTION, + sizeof(v4l2->media_dev.model)); + v4l2->media_dev.hw_revision = 0; + snprintf(v4l2->media_dev.bus_info, + sizeof(v4l2->media_dev.bus_info), "platform:%s", + dev_name(csi_dev->dev)); - media_device_init(&csi->media_dev); - v4l2_async_nf_init(&csi->notifier); + media_device_init(&v4l2->media_dev); + v4l2_async_nf_init(&v4l2->notifier); - ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 0); + ret = v4l2_ctrl_handler_init(&v4l2->ctrl_handler, 0); if (ret) { - dev_err(csi->dev, "V4L2 controls handler init failed (%d)\n", + dev_err(csi_dev->dev, "V4L2 controls handler init failed (%d)\n", ret); goto clean_media; } - csi->v4l2_dev.mdev = &csi->media_dev; - csi->v4l2_dev.ctrl_handler = &csi->ctrl_handler; - ret = v4l2_device_register(csi->dev, &csi->v4l2_dev); + v4l2->v4l2_dev.mdev = &v4l2->media_dev; + v4l2->v4l2_dev.ctrl_handler = &v4l2->ctrl_handler; + ret = v4l2_device_register(csi_dev->dev, &v4l2->v4l2_dev); if (ret) { - dev_err(csi->dev, "V4L2 device registration failed (%d)\n", + dev_err(csi_dev->dev, "V4L2 device registration failed (%d)\n", ret); goto free_ctrl; } - ret = sun6i_video_init(&csi->video, csi, SUN6I_CSI_NAME); + ret = sun6i_video_init(&csi_dev->video, csi_dev, SUN6I_CSI_NAME); if (ret) goto unreg_v4l2; - ret = v4l2_async_nf_parse_fwnode_endpoints(csi->dev, - &csi->notifier, + ret = v4l2_async_nf_parse_fwnode_endpoints(csi_dev->dev, + &v4l2->notifier, sizeof(struct v4l2_async_subdev), sun6i_csi_fwnode_parse); if (ret) goto clean_video; - csi->notifier.ops = &sun6i_csi_async_ops; + v4l2->notifier.ops = &sun6i_csi_async_ops; - ret = v4l2_async_nf_register(&csi->v4l2_dev, &csi->notifier); + ret = v4l2_async_nf_register(&v4l2->v4l2_dev, &v4l2->notifier); if (ret) { - dev_err(csi->dev, "notifier registration failed\n"); + dev_err(csi_dev->dev, "notifier registration failed\n"); goto clean_video; } return 0; clean_video: - sun6i_video_cleanup(&csi->video); + sun6i_video_cleanup(&csi_dev->video); unreg_v4l2: - v4l2_device_unregister(&csi->v4l2_dev); + v4l2_device_unregister(&v4l2->v4l2_dev); free_ctrl: - v4l2_ctrl_handler_free(&csi->ctrl_handler); + v4l2_ctrl_handler_free(&v4l2->ctrl_handler); clean_media: - v4l2_async_nf_cleanup(&csi->notifier); - media_device_cleanup(&csi->media_dev); + v4l2_async_nf_cleanup(&v4l2->notifier); + media_device_cleanup(&v4l2->media_dev); return ret; } @@ -793,8 +781,8 @@ static int sun6i_csi_v4l2_init(struct sun6i_csi *csi) */ static irqreturn_t sun6i_csi_isr(int irq, void *dev_id) { - struct sun6i_csi_dev *sdev = (struct sun6i_csi_dev *)dev_id; - struct regmap *regmap = sdev->regmap; + struct sun6i_csi_device *csi_dev = (struct sun6i_csi_device *)dev_id; + struct regmap *regmap = csi_dev->regmap; u32 status; regmap_read(regmap, CSI_CH_INT_STA_REG, &status); @@ -814,7 +802,7 @@ static irqreturn_t sun6i_csi_isr(int irq, void *dev_id) } if (status & CSI_CH_INT_STA_FD_PD) - sun6i_video_frame_done(&sdev->csi.video); + sun6i_video_frame_done(&csi_dev->video); regmap_write(regmap, CSI_CH_INT_STA_REG, status); @@ -828,7 +816,7 @@ static const struct regmap_config sun6i_csi_regmap_config = { .max_register = 0x9c, }; -static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev, +static int sun6i_csi_resource_request(struct sun6i_csi_device *csi_dev, struct platform_device *pdev) { void __iomem *io_base; @@ -839,29 +827,29 @@ static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev, if (IS_ERR(io_base)) return PTR_ERR(io_base); - sdev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base, - &sun6i_csi_regmap_config); - if (IS_ERR(sdev->regmap)) { + csi_dev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base, + &sun6i_csi_regmap_config); + if (IS_ERR(csi_dev->regmap)) { dev_err(&pdev->dev, "Failed to init register map\n"); - return PTR_ERR(sdev->regmap); + return PTR_ERR(csi_dev->regmap); } - sdev->clk_mod = devm_clk_get(&pdev->dev, "mod"); - if (IS_ERR(sdev->clk_mod)) { + csi_dev->clk_mod = devm_clk_get(&pdev->dev, "mod"); + if (IS_ERR(csi_dev->clk_mod)) { dev_err(&pdev->dev, "Unable to acquire csi clock\n"); - return PTR_ERR(sdev->clk_mod); + return PTR_ERR(csi_dev->clk_mod); } - sdev->clk_ram = devm_clk_get(&pdev->dev, "ram"); - if (IS_ERR(sdev->clk_ram)) { + csi_dev->clk_ram = devm_clk_get(&pdev->dev, "ram"); + if (IS_ERR(csi_dev->clk_ram)) { dev_err(&pdev->dev, "Unable to acquire dram-csi clock\n"); - return PTR_ERR(sdev->clk_ram); + return PTR_ERR(csi_dev->clk_ram); } - sdev->rstc_bus = devm_reset_control_get_shared(&pdev->dev, NULL); - if (IS_ERR(sdev->rstc_bus)) { + csi_dev->reset = devm_reset_control_get_shared(&pdev->dev, NULL); + if (IS_ERR(csi_dev->reset)) { dev_err(&pdev->dev, "Cannot get reset controller\n"); - return PTR_ERR(sdev->rstc_bus); + return PTR_ERR(csi_dev->reset); } irq = platform_get_irq(pdev, 0); @@ -869,7 +857,7 @@ static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev, return -ENXIO; ret = devm_request_irq(&pdev->dev, irq, sun6i_csi_isr, 0, - SUN6I_CSI_NAME, sdev); + SUN6I_CSI_NAME, csi_dev); if (ret) { dev_err(&pdev->dev, "Cannot request csi IRQ\n"); return ret; @@ -880,30 +868,29 @@ static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev, static int sun6i_csi_probe(struct platform_device *pdev) { - struct sun6i_csi_dev *sdev; + struct sun6i_csi_device *csi_dev; int ret; - sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL); - if (!sdev) + csi_dev = devm_kzalloc(&pdev->dev, sizeof(*csi_dev), GFP_KERNEL); + if (!csi_dev) return -ENOMEM; - sdev->dev = &pdev->dev; + csi_dev->dev = &pdev->dev; - ret = sun6i_csi_resource_request(sdev, pdev); + ret = sun6i_csi_resource_request(csi_dev, pdev); if (ret) return ret; - platform_set_drvdata(pdev, sdev); + platform_set_drvdata(pdev, csi_dev); - sdev->csi.dev = &pdev->dev; - return sun6i_csi_v4l2_init(&sdev->csi); + return sun6i_csi_v4l2_init(csi_dev); } static int sun6i_csi_remove(struct platform_device *pdev) { - struct sun6i_csi_dev *sdev = platform_get_drvdata(pdev); + struct sun6i_csi_device *csi_dev = platform_get_drvdata(pdev); - sun6i_csi_v4l2_cleanup(&sdev->csi); + sun6i_csi_v4l2_cleanup(csi_dev); return 0; } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index e04f3c3fa27b..e4e7ac6c869f 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -17,8 +17,6 @@ #define SUN6I_CSI_NAME "sun6i-csi" #define SUN6I_CSI_DESCRIPTION "Allwinner A31 CSI Device" -struct sun6i_csi; - /** * struct sun6i_csi_config - configs for sun6i csi * @pixelformat: v4l2 pixel format (V4L2_PIX_FMT_*) @@ -35,20 +33,29 @@ struct sun6i_csi_config { u32 height; }; -struct sun6i_csi { - struct device *dev; - struct v4l2_ctrl_handler ctrl_handler; +struct sun6i_csi_v4l2 { struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler ctrl_handler; struct media_device media_dev; struct v4l2_async_notifier notifier; - /* video port settings */ struct v4l2_fwnode_endpoint v4l2_ep; +}; - struct sun6i_csi_config config; +struct sun6i_csi_device { + struct device *dev; + struct sun6i_csi_config config; + struct sun6i_csi_v4l2 v4l2; struct sun6i_video video; + + struct regmap *regmap; + struct clk *clk_mod; + struct clk *clk_ram; + struct reset_control *reset; + + int planar_offset[3]; }; /** @@ -57,22 +64,22 @@ struct sun6i_csi { * @pixformat: v4l2 pixel format (V4L2_PIX_FMT_*) * @mbus_code: media bus format code (MEDIA_BUS_FMT_*) */ -bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, u32 pixformat, - u32 mbus_code); +bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev, + u32 pixformat, u32 mbus_code); /** * sun6i_csi_set_power() - power on/off the csi * @csi: pointer to the csi * @enable: on/off */ -int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable); +int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable); /** * sun6i_csi_update_config() - update the csi register settings * @csi: pointer to the csi * @config: see struct sun6i_csi_config */ -int sun6i_csi_update_config(struct sun6i_csi *csi, +int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev, struct sun6i_csi_config *config); /** @@ -80,14 +87,15 @@ int sun6i_csi_update_config(struct sun6i_csi *csi, * @csi: pointer to the csi * @addr: frame buffer's physical address */ -void sun6i_csi_update_buf_addr(struct sun6i_csi *csi, dma_addr_t addr); +void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev, + dma_addr_t addr); /** * sun6i_csi_set_stream() - start/stop csi streaming * @csi: pointer to the csi * @enable: start/stop */ -void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable); +void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable); /* get bpp form v4l2 pixformat */ static inline int sun6i_csi_get_bpp(unsigned int pixformat) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index 607a8d39fbe2..c152c0ceb6d5 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -162,7 +162,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) config.width = video->fmt.fmt.pix.width; config.height = video->fmt.fmt.pix.height; - ret = sun6i_csi_update_config(video->csi, &config); + ret = sun6i_csi_update_config(video->csi_dev, &config); if (ret < 0) goto stop_media_pipeline; @@ -171,9 +171,9 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) buf = list_first_entry(&video->dma_queue, struct sun6i_csi_buffer, list); buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi, buf->dma_addr); + sun6i_csi_update_buf_addr(video->csi_dev, buf->dma_addr); - sun6i_csi_set_stream(video->csi, true); + sun6i_csi_set_stream(video->csi_dev, true); /* * CSI will lookup the next dma buffer for next frame before the @@ -194,7 +194,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) */ next_buf = list_next_entry(buf, list); next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr); + sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr); spin_unlock_irqrestore(&video->dma_queue_lock, flags); @@ -205,7 +205,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) return 0; stop_csi_stream: - sun6i_csi_set_stream(video->csi, false); + sun6i_csi_set_stream(video->csi_dev, false); stop_media_pipeline: media_pipeline_stop(&video->vdev.entity); clear_dma_queue: @@ -229,7 +229,7 @@ static void sun6i_video_stop_streaming(struct vb2_queue *vq) if (subdev) v4l2_subdev_call(subdev, video, s_stream, 0); - sun6i_csi_set_stream(video->csi, false); + sun6i_csi_set_stream(video->csi_dev, false); media_pipeline_stop(&video->vdev.entity); @@ -266,7 +266,7 @@ void sun6i_video_frame_done(struct sun6i_video *video) buf = list_first_entry(&video->dma_queue, struct sun6i_csi_buffer, list); if (list_is_last(&buf->list, &video->dma_queue)) { - dev_dbg(video->csi->dev, "Frame dropped!\n"); + dev_dbg(video->csi_dev->dev, "Frame dropped!\n"); goto unlock; } @@ -278,8 +278,8 @@ void sun6i_video_frame_done(struct sun6i_video *video) */ if (!next_buf->queued_to_csi) { next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr); - dev_dbg(video->csi->dev, "Frame dropped!\n"); + sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr); + dev_dbg(video->csi_dev->dev, "Frame dropped!\n"); goto unlock; } @@ -293,9 +293,9 @@ void sun6i_video_frame_done(struct sun6i_video *video) if (!list_is_last(&next_buf->list, &video->dma_queue)) { next_buf = list_next_entry(next_buf, list); next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr); + sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr); } else { - dev_dbg(video->csi->dev, "Next frame will be dropped!\n"); + dev_dbg(video->csi_dev->dev, "Next frame will be dropped!\n"); } unlock: @@ -321,7 +321,7 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, "sun6i-video", sizeof(cap->driver)); strscpy(cap->card, video->vdev.name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - video->csi->dev->of_node->name); + video->csi_dev->dev->of_node->name); return 0; } @@ -484,7 +484,7 @@ static int sun6i_video_open(struct file *file) if (!v4l2_fh_is_singular_file(file)) goto unlock; - ret = sun6i_csi_set_power(video->csi, true); + ret = sun6i_csi_set_power(video->csi_dev, true); if (ret < 0) goto fh_release; @@ -512,7 +512,7 @@ static int sun6i_video_close(struct file *file) v4l2_pipeline_pm_put(&video->vdev.entity); if (last_fh) - sun6i_csi_set_power(video->csi, false); + sun6i_csi_set_power(video->csi_dev, false); mutex_unlock(&video->lock); @@ -557,7 +557,7 @@ static int sun6i_video_link_validate(struct media_link *link) video->mbus_code = 0; if (!media_entity_remote_pad(link->sink->entity->pads)) { - dev_info(video->csi->dev, + dev_info(video->csi_dev->dev, "video node %s pad not connected\n", vdev->name); return -ENOLINK; } @@ -566,10 +566,10 @@ static int sun6i_video_link_validate(struct media_link *link) if (ret < 0) return ret; - if (!sun6i_csi_is_format_supported(video->csi, + if (!sun6i_csi_is_format_supported(video->csi_dev, video->fmt.fmt.pix.pixelformat, source_fmt.format.code)) { - dev_err(video->csi->dev, + dev_err(video->csi_dev->dev, "Unsupported pixformat: 0x%x with mbus code: 0x%x!\n", video->fmt.fmt.pix.pixelformat, source_fmt.format.code); @@ -578,7 +578,7 @@ static int sun6i_video_link_validate(struct media_link *link) if (source_fmt.format.width != video->fmt.fmt.pix.width || source_fmt.format.height != video->fmt.fmt.pix.height) { - dev_err(video->csi->dev, + dev_err(video->csi_dev->dev, "Wrong width or height %ux%u (%ux%u expected)\n", video->fmt.fmt.pix.width, video->fmt.fmt.pix.height, source_fmt.format.width, source_fmt.format.height); @@ -594,15 +594,16 @@ static const struct media_entity_operations sun6i_video_media_ops = { .link_validate = sun6i_video_link_validate }; -int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, - const char *name) +int sun6i_video_init(struct sun6i_video *video, + struct sun6i_csi_device *csi_dev, const char *name) { + struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; struct video_device *vdev = &video->vdev; struct vb2_queue *vidq = &video->vb2_vidq; struct v4l2_format fmt = { 0 }; int ret; - video->csi = csi; + video->csi_dev = csi_dev; /* Initialize the media entity... */ video->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; @@ -637,11 +638,12 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, vidq->lock = &video->lock; /* Make sure non-dropped frame */ vidq->min_buffers_needed = 3; - vidq->dev = csi->dev; + vidq->dev = csi_dev->dev; ret = vb2_queue_init(vidq); if (ret) { - v4l2_err(&csi->v4l2_dev, "vb2_queue_init failed: %d\n", ret); + v4l2_err(&v4l2->v4l2_dev, "vb2_queue_init failed: %d\n", + ret); goto clean_entity; } @@ -652,7 +654,7 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, vdev->ioctl_ops = &sun6i_video_ioctl_ops; vdev->vfl_type = VFL_TYPE_VIDEO; vdev->vfl_dir = VFL_DIR_RX; - vdev->v4l2_dev = &csi->v4l2_dev; + vdev->v4l2_dev = &v4l2->v4l2_dev; vdev->queue = vidq; vdev->lock = &video->lock; vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; @@ -660,7 +662,7 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret < 0) { - v4l2_err(&csi->v4l2_dev, + v4l2_err(&v4l2->v4l2_dev, "video_register_device failed: %d\n", ret); goto clean_entity; } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h index b9cd919c24ac..30e37ee0d07f 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h @@ -11,12 +11,12 @@ #include #include -struct sun6i_csi; +struct sun6i_csi_device; struct sun6i_video { + struct sun6i_csi_device *csi_dev; struct video_device vdev; struct media_pad pad; - struct sun6i_csi *csi; struct mutex lock; @@ -29,8 +29,8 @@ struct sun6i_video { u32 mbus_code; }; -int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, - const char *name); +int sun6i_video_init(struct sun6i_video *video, + struct sun6i_csi_device *csi_dev, const char *name); void sun6i_video_cleanup(struct sun6i_video *video); void sun6i_video_frame_done(struct sun6i_video *video); From patchwork Fri Mar 11 14:34:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778110 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0EEF0C433EF for ; Fri, 11 Mar 2022 14:36:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243998AbiCKOhE (ORCPT ); Fri, 11 Mar 2022 09:37:04 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58488 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349411AbiCKOhB (ORCPT ); Fri, 11 Mar 2022 09:37:01 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 280411C8D9E; Fri, 11 Mar 2022 06:35:57 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 456D1240004; Fri, 11 Mar 2022 14:35:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009356; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=tUV9pToXc97GruDFUILdAEx8PuuZu4dV5AXoi5Yg5kY=; b=OCg9rH7jIUCvz9N3IkVUtWDFo+Fq7PJnwOBs4ZJ63qVflQlRjD5xXd1Aj0oClc3u5bJhJc RhQ+2dQ3bDtH1AMhFiUYKw7Vw5ksTVuAu49bg+y4IAF1bNi5mZKPJSwEp+O7j/TAxFWNw9 HzRz/NpT5gK4ezzvLWigf5AHEsd56Nd85ls9B+qobInxF0xcGoBI3O3C9cufsUTSH3EHWt ijkm9MMfl7j+kqB6cWQmagcrJOWgxNKCj0WJRgF1JisBvWzQzkicVS4/pSyAzqNXACSHoo pEElKKV+v0/a6+dBhtmrLpwJhRXdpXWcnbYZOpcKeKBpUSy+KA/K7glrLlpV0w== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 03/46] media: sun6i-csi: Grab bus clock instead of passing it to regmap Date: Fri, 11 Mar 2022 15:34:49 +0100 Message-Id: <20220311143532.265091-4-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Since the bus clock alone is not enough to get access to the registers, don't pass it to regmap and manage it instead just like the other clocks. Signed-off-by: Paul Kocialkowski --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 10 ++++++++-- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 5fbaa1e99412..dc79f3c14336 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -827,13 +827,19 @@ static int sun6i_csi_resource_request(struct sun6i_csi_device *csi_dev, if (IS_ERR(io_base)) return PTR_ERR(io_base); - csi_dev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base, - &sun6i_csi_regmap_config); + csi_dev->regmap = devm_regmap_init_mmio(&pdev->dev, io_base, + &sun6i_csi_regmap_config); if (IS_ERR(csi_dev->regmap)) { dev_err(&pdev->dev, "Failed to init register map\n"); return PTR_ERR(csi_dev->regmap); } + csi_dev->clk_bus = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(csi_dev->clk_bus)) { + dev_err(&pdev->dev, "Unable to acquire bus clock\n"); + return PTR_ERR(csi_dev->clk_bus); + } + csi_dev->clk_mod = devm_clk_get(&pdev->dev, "mod"); if (IS_ERR(csi_dev->clk_mod)) { dev_err(&pdev->dev, "Unable to acquire csi clock\n"); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index e4e7ac6c869f..356661b413f8 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -51,6 +51,7 @@ struct sun6i_csi_device { struct sun6i_video video; struct regmap *regmap; + struct clk *clk_bus; struct clk *clk_mod; struct clk *clk_ram; struct reset_control *reset; From patchwork Fri Mar 11 14:34:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778111 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B5211C433FE for ; Fri, 11 Mar 2022 14:36:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349423AbiCKOhE (ORCPT ); Fri, 11 Mar 2022 09:37:04 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58510 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349415AbiCKOhD (ORCPT ); Fri, 11 Mar 2022 09:37:03 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5E9381C8DA3; Fri, 11 Mar 2022 06:35:59 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id B3033240014; Fri, 11 Mar 2022 14:35:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009357; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=w/9w4iol/OgR2hA7bibkg4EZnyOwhop/XnEYBOaJEpI=; b=B0RV7CSHOUnTxHpAUVx9T5dtZIA4ERthcyJokO0wCwhPzbzqFRjaPzMQ4ZPjbOSQ8SnOqt Rbvjv23dKjGI/LYcAGN/9sxXAxEin8eLoasf9Me1MM0cu/ITB+SkgOLWVQ0WJdIja41HHd wnuU9+VlMaVS+Oi2fNlsTdK0ZElR2ZTVvvPoD9Gx5pLpIhXFTFa/xcgupp5/HdDAHtQHNb 4PocK8KdvF1iKM5GZDmo265ca3u3dyY1Dk9llZRxe++/Vrq2+tKdWhSp1mFaBM+L8oBcDq XStkh8dhmo1H26T6xBM1EWqCTZGv9dpa1LKSIhPLfeG33mnBXtw4CDB5q5ZLDw== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni , Maxime Ripard Subject: [PATCH v3 04/46] media: sun6i-csi: Tidy up platform code Date: Fri, 11 Mar 2022 15:34:50 +0100 Message-Id: <20220311143532.265091-5-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Various renames, variables lowering and other cosmetic changes in the platform-support code. No functional change intended. Signed-off-by: Paul Kocialkowski Reviewed-by: Maxime Ripard --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 76 +++++++++++-------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index dc79f3c14336..8155e9560164 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -776,12 +776,11 @@ static int sun6i_csi_v4l2_init(struct sun6i_csi_device *csi_dev) return ret; } -/* ----------------------------------------------------------------------------- - * Resources and IRQ - */ -static irqreturn_t sun6i_csi_isr(int irq, void *dev_id) +/* Platform */ + +static irqreturn_t sun6i_csi_isr(int irq, void *private) { - struct sun6i_csi_device *csi_dev = (struct sun6i_csi_device *)dev_id; + struct sun6i_csi_device *csi_dev = private; struct regmap *regmap = csi_dev->regmap; u32 status; @@ -816,79 +815,88 @@ static const struct regmap_config sun6i_csi_regmap_config = { .max_register = 0x9c, }; -static int sun6i_csi_resource_request(struct sun6i_csi_device *csi_dev, - struct platform_device *pdev) +static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, + struct platform_device *platform_dev) { + struct device *dev = csi_dev->dev; void __iomem *io_base; int ret; int irq; - io_base = devm_platform_ioremap_resource(pdev, 0); + /* Registers */ + + io_base = devm_platform_ioremap_resource(platform_dev, 0); if (IS_ERR(io_base)) return PTR_ERR(io_base); - csi_dev->regmap = devm_regmap_init_mmio(&pdev->dev, io_base, + csi_dev->regmap = devm_regmap_init_mmio(dev, io_base, &sun6i_csi_regmap_config); if (IS_ERR(csi_dev->regmap)) { - dev_err(&pdev->dev, "Failed to init register map\n"); + dev_err(dev, "failed to init register map\n"); return PTR_ERR(csi_dev->regmap); } - csi_dev->clk_bus = devm_clk_get(&pdev->dev, "bus"); + /* Clocks */ + + csi_dev->clk_bus = devm_clk_get(dev, "bus"); if (IS_ERR(csi_dev->clk_bus)) { - dev_err(&pdev->dev, "Unable to acquire bus clock\n"); + dev_err(dev, "failed to acquire bus clock\n"); return PTR_ERR(csi_dev->clk_bus); } - csi_dev->clk_mod = devm_clk_get(&pdev->dev, "mod"); + csi_dev->clk_mod = devm_clk_get(dev, "mod"); if (IS_ERR(csi_dev->clk_mod)) { - dev_err(&pdev->dev, "Unable to acquire csi clock\n"); + dev_err(dev, "failed to acquire module clock\n"); return PTR_ERR(csi_dev->clk_mod); } - csi_dev->clk_ram = devm_clk_get(&pdev->dev, "ram"); + csi_dev->clk_ram = devm_clk_get(dev, "ram"); if (IS_ERR(csi_dev->clk_ram)) { - dev_err(&pdev->dev, "Unable to acquire dram-csi clock\n"); + dev_err(dev, "failed to acquire ram clock\n"); return PTR_ERR(csi_dev->clk_ram); } - csi_dev->reset = devm_reset_control_get_shared(&pdev->dev, NULL); + /* Reset */ + + csi_dev->reset = devm_reset_control_get_shared(dev, NULL); if (IS_ERR(csi_dev->reset)) { - dev_err(&pdev->dev, "Cannot get reset controller\n"); + dev_err(dev, "failed to acquire reset\n"); return PTR_ERR(csi_dev->reset); } - irq = platform_get_irq(pdev, 0); + /* Interrupt */ + + irq = platform_get_irq(platform_dev, 0); if (irq < 0) return -ENXIO; - ret = devm_request_irq(&pdev->dev, irq, sun6i_csi_isr, 0, - SUN6I_CSI_NAME, csi_dev); + ret = devm_request_irq(dev, irq, sun6i_csi_isr, 0, SUN6I_CSI_NAME, + csi_dev); if (ret) { - dev_err(&pdev->dev, "Cannot request csi IRQ\n"); + dev_err(dev, "failed to request interrupt\n"); return ret; } return 0; } -static int sun6i_csi_probe(struct platform_device *pdev) +static int sun6i_csi_probe(struct platform_device *platform_dev) { struct sun6i_csi_device *csi_dev; + struct device *dev = &platform_dev->dev; int ret; - csi_dev = devm_kzalloc(&pdev->dev, sizeof(*csi_dev), GFP_KERNEL); + csi_dev = devm_kzalloc(dev, sizeof(*csi_dev), GFP_KERNEL); if (!csi_dev) return -ENOMEM; - csi_dev->dev = &pdev->dev; + csi_dev->dev = &platform_dev->dev; + platform_set_drvdata(platform_dev, csi_dev); - ret = sun6i_csi_resource_request(csi_dev, pdev); + ret = sun6i_csi_resources_setup(csi_dev, platform_dev); if (ret) return ret; - platform_set_drvdata(pdev, csi_dev); - return sun6i_csi_v4l2_init(csi_dev); } @@ -909,16 +917,18 @@ static const struct of_device_id sun6i_csi_of_match[] = { { .compatible = "allwinner,sun50i-a64-csi", }, {}, }; + MODULE_DEVICE_TABLE(of, sun6i_csi_of_match); static struct platform_driver sun6i_csi_platform_driver = { - .probe = sun6i_csi_probe, - .remove = sun6i_csi_remove, - .driver = { - .name = SUN6I_CSI_NAME, - .of_match_table = of_match_ptr(sun6i_csi_of_match), + .probe = sun6i_csi_probe, + .remove = sun6i_csi_remove, + .driver = { + .name = SUN6I_CSI_NAME, + .of_match_table = of_match_ptr(sun6i_csi_of_match), }, }; + module_platform_driver(sun6i_csi_platform_driver); MODULE_DESCRIPTION("Allwinner A31 Camera Sensor Interface driver"); From patchwork Fri Mar 11 14:34:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778112 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8B649C4332F for ; Fri, 11 Mar 2022 14:36:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349436AbiCKOhH (ORCPT ); Fri, 11 Mar 2022 09:37:07 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58522 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349419AbiCKOhE (ORCPT ); Fri, 11 Mar 2022 09:37:04 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 97F7D1C8DA4; Fri, 11 Mar 2022 06:36:00 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id EE790240005; Fri, 11 Mar 2022 14:35:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009359; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=osJFZDLYgAC0fspugFGrGdYz4LqqrPjdk0ybNWCGf6E=; b=OxZaue9a/kjsG7KtVJ2Qznfrr0EA/l8zjAIVPpqQ22B9aEsHmVHVfWwSkBWJ9L6rd85+x4 YSIBKJvTUCeU1XSkCQbQGYigtWswXM1eNOisDUjnOMjszRS/n69AGWOvcqkEcdCPpTbK9v QAu9zK5ORcqK9/OnXp7q3Yjb9wOPknhYKNQHDq13jflODtCN9ahfljCRl93cYllYbCOCy4 fzHK2/n1wOrtH/lKrJ9GjTiVk9dY2FYjuFk/Le81yULVRtbpiSDp+jSJdANaV0x+1AAxni +KjVv8XMoFtlMkBfKU26VRjRPSm2VGPC6RHPwtPcgiw1iqvzNstuPg/DyhGT+Q== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 05/46] media: sun6i-csi: Always set exclusive module clock rate Date: Fri, 11 Mar 2022 15:34:51 +0100 Message-Id: <20220311143532.265091-6-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org In some situations the default rate of the module clock is not the required one for operation (for example when reconfiguring the clock tree to use a different parent). As a result, always set the correct rate for the clock (and take care of cleanup). Signed-off-by: Paul Kocialkowski Reviewed-by: Jernej Skrabec --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 54 ++++++++++++++----- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 8155e9560164..2355088fdc37 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -154,9 +154,6 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0); clk_disable_unprepare(csi_dev->clk_ram); - if (of_device_is_compatible(dev->of_node, - "allwinner,sun50i-a64-csi")) - clk_rate_exclusive_put(csi_dev->clk_mod); clk_disable_unprepare(csi_dev->clk_mod); reset_control_assert(csi_dev->reset); return 0; @@ -168,9 +165,6 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) return ret; } - if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clk_set_rate_exclusive(csi_dev->clk_mod, 300000000); - ret = clk_prepare_enable(csi_dev->clk_ram); if (ret) { dev_err(csi_dev->dev, "Enable clk_dram_csi clk err %d\n", ret); @@ -190,8 +184,6 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) clk_ram_disable: clk_disable_unprepare(csi_dev->clk_ram); clk_mod_disable: - if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clk_rate_exclusive_put(csi_dev->clk_mod); clk_disable_unprepare(csi_dev->clk_mod); return ret; } @@ -819,6 +811,7 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, struct platform_device *platform_dev) { struct device *dev = csi_dev->dev; + unsigned long clk_mod_rate; void __iomem *io_base; int ret; int irq; @@ -856,28 +849,53 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, return PTR_ERR(csi_dev->clk_ram); } + if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) + clk_mod_rate = 300000000; + else + clk_mod_rate = 297000000; + + ret = clk_set_rate_exclusive(csi_dev->clk_mod, clk_mod_rate); + if (ret) { + dev_err(dev, "failed to set mod clock rate\n"); + return ret; + } + /* Reset */ csi_dev->reset = devm_reset_control_get_shared(dev, NULL); if (IS_ERR(csi_dev->reset)) { dev_err(dev, "failed to acquire reset\n"); - return PTR_ERR(csi_dev->reset); + ret = PTR_ERR(csi_dev->reset); + goto error_clk_rate_exclusive; } /* Interrupt */ irq = platform_get_irq(platform_dev, 0); - if (irq < 0) - return -ENXIO; + if (irq < 0) { + dev_err(dev, "failed to get interrupt\n"); + ret = -ENXIO; + goto error_clk_rate_exclusive; + } ret = devm_request_irq(dev, irq, sun6i_csi_isr, 0, SUN6I_CSI_NAME, csi_dev); if (ret) { dev_err(dev, "failed to request interrupt\n"); - return ret; + goto error_clk_rate_exclusive; } return 0; + +error_clk_rate_exclusive: + clk_rate_exclusive_put(csi_dev->clk_mod); + + return ret; +} + +static void sun6i_csi_resources_cleanup(struct sun6i_csi_device *csi_dev) +{ + clk_rate_exclusive_put(csi_dev->clk_mod); } static int sun6i_csi_probe(struct platform_device *platform_dev) @@ -897,7 +915,16 @@ static int sun6i_csi_probe(struct platform_device *platform_dev) if (ret) return ret; - return sun6i_csi_v4l2_init(csi_dev); + ret = sun6i_csi_v4l2_init(csi_dev); + if (ret) + goto error_resources; + + return 0; + +error_resources: + sun6i_csi_resources_cleanup(csi_dev); + + return ret; } static int sun6i_csi_remove(struct platform_device *pdev) @@ -905,6 +932,7 @@ static int sun6i_csi_remove(struct platform_device *pdev) struct sun6i_csi_device *csi_dev = platform_get_drvdata(pdev); sun6i_csi_v4l2_cleanup(csi_dev); + sun6i_csi_resources_cleanup(csi_dev); return 0; } From patchwork Fri Mar 11 14:34:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778114 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6B212C433F5 for ; Fri, 11 Mar 2022 14:36:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349454AbiCKOhN (ORCPT ); Fri, 11 Mar 2022 09:37:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58564 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349428AbiCKOhG (ORCPT ); Fri, 11 Mar 2022 09:37:06 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 20ADA1C8D9C; Fri, 11 Mar 2022 06:36:01 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 3FF9D240002; Fri, 11 Mar 2022 14:35:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009360; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=OtqvGR2qx3fG3mVGNkeVbc6J/VMjoN9TX7j1jYCLPUI=; b=j75vUwWr8uohNCqRwp69wdWywhTHuh+MLlAupqPPyXwlLJ5LpiDzmdtSTIseRc10QLpyyj +VF4mPkCH1Sodlgf0YSb/rwMXrEm3okz6gHGAhRwMyvvuR0Sir2DuUuiyfLMaEr5fNFJLR apNJmgVz0mT99VRVoLO0fUoNsDar+NVQgXpRhf/t4WmCylJ4qPROzNUt+0mu16FKKboosx 9H+4m8lp8EjR1bwMDh3WsytVqjbTFVj18bUPtu87Avswn++Uz4KtDGcc/3RP0mFCPO8bBW JNTHLDF+Jy9CreDbPRRux7cF8plPo8wJRJLJ58iYtOq5/NOzCg1uizaq3tJl2A== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 06/46] media: sun6i-csi: Define and use variant to get module clock rate Date: Fri, 11 Mar 2022 15:34:52 +0100 Message-Id: <20220311143532.265091-7-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Introduce a proper variant structure with the module clock rate instead of hardcoding it with a manual check on the compatible. Signed-off-by: Paul Kocialkowski Reviewed-by: Jernej Skrabec --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 48 ++++++++++++++----- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 4 ++ 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 2355088fdc37..4a0d08e0ac25 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -811,11 +811,17 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, struct platform_device *platform_dev) { struct device *dev = csi_dev->dev; - unsigned long clk_mod_rate; + const struct sun6i_csi_variant *variant; void __iomem *io_base; int ret; int irq; + /* Variant */ + + variant = of_device_get_match_data(dev); + if (!variant) + return -EINVAL; + /* Registers */ io_base = devm_platform_ioremap_resource(platform_dev, 0); @@ -849,12 +855,7 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, return PTR_ERR(csi_dev->clk_ram); } - if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clk_mod_rate = 300000000; - else - clk_mod_rate = 297000000; - - ret = clk_set_rate_exclusive(csi_dev->clk_mod, clk_mod_rate); + ret = clk_set_rate_exclusive(csi_dev->clk_mod, variant->clk_mod_rate); if (ret) { dev_err(dev, "failed to set mod clock rate\n"); return ret; @@ -937,12 +938,35 @@ static int sun6i_csi_remove(struct platform_device *pdev) return 0; } +static const struct sun6i_csi_variant sun6i_a31_csi_variant = { + .clk_mod_rate = 297000000, +}; + +static const struct sun6i_csi_variant sun50i_a64_csi_variant = { + .clk_mod_rate = 300000000, +}; + static const struct of_device_id sun6i_csi_of_match[] = { - { .compatible = "allwinner,sun6i-a31-csi", }, - { .compatible = "allwinner,sun8i-a83t-csi", }, - { .compatible = "allwinner,sun8i-h3-csi", }, - { .compatible = "allwinner,sun8i-v3s-csi", }, - { .compatible = "allwinner,sun50i-a64-csi", }, + { + .compatible = "allwinner,sun6i-a31-csi", + .data = &sun6i_a31_csi_variant, + }, + { + .compatible = "allwinner,sun8i-a83t-csi", + .data = &sun6i_a31_csi_variant, + }, + { + .compatible = "allwinner,sun8i-h3-csi", + .data = &sun6i_a31_csi_variant, + }, + { + .compatible = "allwinner,sun8i-v3s-csi", + .data = &sun6i_a31_csi_variant, + }, + { + .compatible = "allwinner,sun50i-a64-csi", + .data = &sun50i_a64_csi_variant, + }, {}, }; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 356661b413f8..3c4a3af6b897 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -59,6 +59,10 @@ struct sun6i_csi_device { int planar_offset[3]; }; +struct sun6i_csi_variant { + unsigned long clk_mod_rate; +}; + /** * sun6i_csi_is_format_supported() - check if the format supported by csi * @csi: pointer to the csi From patchwork Fri Mar 11 14:34:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778115 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 10108C4332F for ; Fri, 11 Mar 2022 14:36:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349458AbiCKOhO (ORCPT ); Fri, 11 Mar 2022 09:37:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58638 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349434AbiCKOhH (ORCPT ); Fri, 11 Mar 2022 09:37:07 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 569251C8DA8; Fri, 11 Mar 2022 06:36:03 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id A6C7F240015; Fri, 11 Mar 2022 14:36:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009361; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cz8N6RvCKaWbZnNFxdRWzzyjz/M3Rp7k8RHQ9h9A25A=; b=VWKJCbJZfcFbt1P+JijpBUMqVYtOVeEKdYJ6rQXigSvs/0v5bE9XgfVXj49qa1ObiUC44i shZwhoMYdYUwTsN+aFEhBX++DaCFs8cSE97g9aaB+Ru16z/6GORXXFGEcWEdRswOj9Iu16 YISDkvqwv6gI7P0DQxMAnOqtq1j2+4GCuAG44CPN93du2z20u8nQ0uRYajMP4upQSiwLRK kKIjqUZHHkg9L0Jfig4XJYXEgHuFHUKtj9umo/HZu/J4SunbdzZSJnhQEH38pweg6Rsj5V lk2Vq4S57k53U24i6hofV5wrHMZ9HeNe9NOVIYMrJS2uKdT/09RsSdUMYzpCgA== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 07/46] media: sun6i-csi: Use runtime pm for clocks and reset Date: Fri, 11 Mar 2022 15:34:53 +0100 Message-Id: <20220311143532.265091-8-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Wrap the clock and reset preparation into runtime pm functions for better organization of the code. Also fix the clock and reset enable order to first deassert reset, as recommended in Allwinner litterature. Make the driver depend on PM while at it since runtime pm is mandatory for the driver to work. Signed-off-by: Paul Kocialkowski --- .../media/platform/sunxi/sun6i-csi/Kconfig | 2 +- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 94 ++++++++++++++----- 2 files changed, 70 insertions(+), 26 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/Kconfig b/drivers/media/platform/sunxi/sun6i-csi/Kconfig index 586e3fb3a80d..fd03e48f0c8a 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/Kconfig +++ b/drivers/media/platform/sunxi/sun6i-csi/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_SUN6I_CSI tristate "Allwinner V3s Camera Sensor Interface driver" - depends on VIDEO_V4L2 && COMMON_CLK && HAS_DMA + depends on PM && VIDEO_V4L2 && COMMON_CLK && HAS_DMA depends on ARCH_SUNXI || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 4a0d08e0ac25..7f045a9551a7 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -152,40 +152,18 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) if (!enable) { regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0); + pm_runtime_put(dev); - clk_disable_unprepare(csi_dev->clk_ram); - clk_disable_unprepare(csi_dev->clk_mod); - reset_control_assert(csi_dev->reset); return 0; } - ret = clk_prepare_enable(csi_dev->clk_mod); - if (ret) { - dev_err(csi_dev->dev, "Enable csi clk err %d\n", ret); + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) return ret; - } - - ret = clk_prepare_enable(csi_dev->clk_ram); - if (ret) { - dev_err(csi_dev->dev, "Enable clk_dram_csi clk err %d\n", ret); - goto clk_mod_disable; - } - - ret = reset_control_deassert(csi_dev->reset); - if (ret) { - dev_err(csi_dev->dev, "reset err %d\n", ret); - goto clk_ram_disable; - } regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, CSI_EN_CSI_EN); return 0; - -clk_ram_disable: - clk_disable_unprepare(csi_dev->clk_ram); -clk_mod_disable: - clk_disable_unprepare(csi_dev->clk_mod); - return ret; } static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_device *csi_dev, @@ -800,6 +778,65 @@ static irqreturn_t sun6i_csi_isr(int irq, void *private) return IRQ_HANDLED; } +static int sun6i_csi_suspend(struct device *dev) +{ + struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); + + reset_control_assert(csi_dev->reset); + clk_disable_unprepare(csi_dev->clk_ram); + clk_disable_unprepare(csi_dev->clk_mod); + clk_disable_unprepare(csi_dev->clk_bus); + + return 0; +} + +static int sun6i_csi_resume(struct device *dev) +{ + struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); + int ret; + + ret = reset_control_deassert(csi_dev->reset); + if (ret) { + dev_err(dev, "failed to deassert reset\n"); + return ret; + } + + ret = clk_prepare_enable(csi_dev->clk_bus); + if (ret) { + dev_err(dev, "failed to enable bus clock\n"); + goto error_reset; + } + + ret = clk_prepare_enable(csi_dev->clk_mod); + if (ret) { + dev_err(dev, "failed to enable module clock\n"); + goto error_clk_bus; + } + + ret = clk_prepare_enable(csi_dev->clk_ram); + if (ret) { + dev_err(dev, "failed to enable ram clock\n"); + goto error_clk_mod; + } + + return 0; + +error_clk_mod: + clk_disable_unprepare(csi_dev->clk_mod); + +error_clk_bus: + clk_disable_unprepare(csi_dev->clk_bus); + +error_reset: + reset_control_assert(csi_dev->reset); + + return ret; +} + +static const struct dev_pm_ops sun6i_csi_pm_ops = { + SET_RUNTIME_PM_OPS(sun6i_csi_suspend, sun6i_csi_resume, NULL) +}; + static const struct regmap_config sun6i_csi_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -886,6 +923,11 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, goto error_clk_rate_exclusive; } + /* Runtime PM */ + + pm_runtime_enable(dev); + pm_runtime_set_suspended(dev); + return 0; error_clk_rate_exclusive: @@ -896,6 +938,7 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, static void sun6i_csi_resources_cleanup(struct sun6i_csi_device *csi_dev) { + pm_runtime_disable(csi_dev->dev); clk_rate_exclusive_put(csi_dev->clk_mod); } @@ -978,6 +1021,7 @@ static struct platform_driver sun6i_csi_platform_driver = { .driver = { .name = SUN6I_CSI_NAME, .of_match_table = of_match_ptr(sun6i_csi_of_match), + .pm = &sun6i_csi_pm_ops, }, }; From patchwork Fri Mar 11 14:34:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778116 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 308AFC433F5 for ; Fri, 11 Mar 2022 14:36:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349414AbiCKOhR (ORCPT ); Fri, 11 Mar 2022 09:37:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58770 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349445AbiCKOhM (ORCPT ); Fri, 11 Mar 2022 09:37:12 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E310F1C8D9E; Fri, 11 Mar 2022 06:36:04 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 231D1240018; Fri, 11 Mar 2022 14:36:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009363; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9fk7QR84y0sUuiS1RoyQ7eIcmi41dnOp0E0reQwiR4Y=; b=klA4LHBqU+S1tB1GBVhZWxLtLS8l/ivVVfPxo+IjngltmmmlgVFKjQHjbj6NLaVuaWoxUI KnXVce1WhmrJCQm+jq+dPo7tt6H2Zm8XqdmTSMPWA5lEKJuLHpYfr/s87577gaUKs4ejU5 LVLjAxMIOop6IH4TLF69M8wMQyaRmmHAIuLLQgp2sjQocLaKPd5gjuoOQbBg6pp+weYitS /EE64V80kiGqb+31UyNO3OhjMhV22foqzJ+TkOt6ivrKQUkaIKNIoO/zQ8fl9K4toIS1lb Kyh2iDqGggN5C0ILIqnW1hbA0nlaGM95wbQYsLClW5pnEVS7uLDFzmlC2QYVww== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 08/46] media: sun6i-csi: Tidy up Kconfig Date: Fri, 11 Mar 2022 15:34:54 +0100 Message-Id: <20220311143532.265091-9-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Update the option title and help, group related options together, add dependency on VIDEO_DEV since the driver uses it. Signed-off-by: Paul Kocialkowski --- drivers/media/platform/sunxi/sun6i-csi/Kconfig | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/Kconfig b/drivers/media/platform/sunxi/sun6i-csi/Kconfig index fd03e48f0c8a..a88978eba455 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/Kconfig +++ b/drivers/media/platform/sunxi/sun6i-csi/Kconfig @@ -1,12 +1,13 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_SUN6I_CSI - tristate "Allwinner V3s Camera Sensor Interface driver" - depends on PM && VIDEO_V4L2 && COMMON_CLK && HAS_DMA + tristate "Allwinner A31 Camera Sensor Interface (CSI) Driver" depends on ARCH_SUNXI || COMPILE_TEST + depends on PM && COMMON_CLK && HAS_DMA + depends on VIDEO_DEV && VIDEO_V4L2 + select REGMAP_MMIO select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG - select REGMAP_MMIO select V4L2_FWNODE help - Support for the Allwinner Camera Sensor Interface Controller on V3s. + Support for the Allwinner A31 Camera Sensor Interface (CSI) controller. From patchwork Fri Mar 11 14:34:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778117 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5BC29C433EF for ; Fri, 11 Mar 2022 14:36:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349466AbiCKOha (ORCPT ); Fri, 11 Mar 2022 09:37:30 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58864 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349463AbiCKOhP (ORCPT ); Fri, 11 Mar 2022 09:37:15 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 338AB1C9442; Fri, 11 Mar 2022 06:36:05 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 752D9240004; Fri, 11 Mar 2022 14:36:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009364; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=UJMB+Dq/MKY7u+TyohX6LA6RXMluwS3R80fT4Bz7iu4=; b=Gi1N/7HI0RSf0eirsq6TJ5II8fBgJhqS8vyzWMyQTuZW/oCeKt93nCAMldvtd8nRhdOKvz BDJ+AdtWW5JPVn0fFTBnxMDbVjM2K5lzCUXWOrTFjoF/u26J1lKrebrr+uvnr6pFDjoXZX Cl5FQjLPYN57td+jmQEZQg4wxHJ2ZrgDoq0qRqCxWvGPhKigurWJIfYHIssjkKB2KZbpac H0x1llu4r/gQf61DuDQ0ArmSDM0uMkBbtlk8ZRyK6Uojn8mIyZZ5XElys52Uyl3i7zVtUb o7wMtFwLszur8lSS0X2RyfeQm5EsMlEqHoCYbnkhTUuv9Mr8Zi82ySDUQAY4EQ== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni , Maxime Ripard Subject: [PATCH v3 09/46] media: sun6i-csi: Tidy up v4l2 code Date: Fri, 11 Mar 2022 15:34:55 +0100 Message-Id: <20220311143532.265091-10-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Various cosmetic improvements to the v4l2 registration code, with renames, lowerings, etc. The cleanup function is moved down after setup. No functional change intended. Signed-off-by: Paul Kocialkowski Reviewed-by: Maxime Ripard --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 118 ++++++++++-------- 1 file changed, 68 insertions(+), 50 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 7f045a9551a7..1f694847ca65 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -27,6 +27,8 @@ #include "sun6i_csi.h" #include "sun6i_csi_reg.h" +/* Helpers */ + /* TODO add 10&12 bit YUV, RGB support */ bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev, u32 pixformat, u32 mbus_code) @@ -572,9 +574,8 @@ void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable) CSI_CAP_CH0_VCAP_ON); } -/* ----------------------------------------------------------------------------- - * Media Controller and V4L2 - */ +/* V4L2 */ + static int sun6i_csi_link_entity(struct sun6i_csi_device *csi_dev, struct media_entity *entity, struct fwnode_handle *fwnode) @@ -666,86 +667,103 @@ static int sun6i_csi_fwnode_parse(struct device *dev, } } -static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev) +static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) { struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; + struct media_device *media_dev = &v4l2->media_dev; + struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev; + struct v4l2_async_notifier *notifier = &v4l2->notifier; + struct device *dev = csi_dev->dev; + int ret; - media_device_unregister(&v4l2->media_dev); - v4l2_async_nf_unregister(&v4l2->notifier); - v4l2_async_nf_cleanup(&v4l2->notifier); - sun6i_video_cleanup(&csi_dev->video); - v4l2_device_unregister(&v4l2->v4l2_dev); - v4l2_ctrl_handler_free(&v4l2->ctrl_handler); - media_device_cleanup(&v4l2->media_dev); -} + /* Media Device */ -static int sun6i_csi_v4l2_init(struct sun6i_csi_device *csi_dev) -{ - struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; - int ret; + strscpy(media_dev->model, SUN6I_CSI_DESCRIPTION, + sizeof(media_dev->model)); + snprintf(media_dev->bus_info, sizeof(media_dev->bus_info), + "platform:%s", dev_name(dev)); + media_dev->hw_revision = 0; + media_dev->dev = dev; - v4l2->media_dev.dev = csi_dev->dev; - strscpy(v4l2->media_dev.model, SUN6I_CSI_DESCRIPTION, - sizeof(v4l2->media_dev.model)); - v4l2->media_dev.hw_revision = 0; - snprintf(v4l2->media_dev.bus_info, - sizeof(v4l2->media_dev.bus_info), "platform:%s", - dev_name(csi_dev->dev)); + media_device_init(media_dev); - media_device_init(&v4l2->media_dev); - v4l2_async_nf_init(&v4l2->notifier); + /* V4L2 Control Handler */ ret = v4l2_ctrl_handler_init(&v4l2->ctrl_handler, 0); if (ret) { - dev_err(csi_dev->dev, "V4L2 controls handler init failed (%d)\n", - ret); - goto clean_media; + dev_err(dev, "failed to init v4l2 control handler: %d\n", ret); + goto error_media; } - v4l2->v4l2_dev.mdev = &v4l2->media_dev; - v4l2->v4l2_dev.ctrl_handler = &v4l2->ctrl_handler; - ret = v4l2_device_register(csi_dev->dev, &v4l2->v4l2_dev); + /* V4L2 Device */ + + v4l2_dev->mdev = media_dev; + v4l2_dev->ctrl_handler = &v4l2->ctrl_handler; + + ret = v4l2_device_register(dev, v4l2_dev); if (ret) { - dev_err(csi_dev->dev, "V4L2 device registration failed (%d)\n", - ret); - goto free_ctrl; + dev_err(dev, "failed to register v4l2 device: %d\n", ret); + goto error_v4l2_ctrl; } + /* Video */ + ret = sun6i_video_init(&csi_dev->video, csi_dev, SUN6I_CSI_NAME); if (ret) - goto unreg_v4l2; + goto error_v4l2_device; - ret = v4l2_async_nf_parse_fwnode_endpoints(csi_dev->dev, - &v4l2->notifier, + /* V4L2 Async */ + + v4l2_async_nf_init(notifier); + notifier->ops = &sun6i_csi_async_ops; + + ret = v4l2_async_nf_parse_fwnode_endpoints(dev, notifier, sizeof(struct v4l2_async_subdev), sun6i_csi_fwnode_parse); if (ret) - goto clean_video; - - v4l2->notifier.ops = &sun6i_csi_async_ops; + goto error_video; - ret = v4l2_async_nf_register(&v4l2->v4l2_dev, &v4l2->notifier); + ret = v4l2_async_nf_register(v4l2_dev, notifier); if (ret) { - dev_err(csi_dev->dev, "notifier registration failed\n"); - goto clean_video; + dev_err(dev, "failed to register v4l2 async notifier: %d\n", + ret); + goto error_v4l2_async_notifier; } return 0; -clean_video: +error_v4l2_async_notifier: + v4l2_async_nf_cleanup(notifier); + +error_video: sun6i_video_cleanup(&csi_dev->video); -unreg_v4l2: + +error_v4l2_device: v4l2_device_unregister(&v4l2->v4l2_dev); -free_ctrl: + +error_v4l2_ctrl: v4l2_ctrl_handler_free(&v4l2->ctrl_handler); -clean_media: - v4l2_async_nf_cleanup(&v4l2->notifier); - media_device_cleanup(&v4l2->media_dev); + +error_media: + media_device_cleanup(media_dev); return ret; } +static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev) +{ + struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; + + media_device_unregister(&v4l2->media_dev); + v4l2_async_nf_unregister(&v4l2->notifier); + v4l2_async_nf_cleanup(&v4l2->notifier); + sun6i_video_cleanup(&csi_dev->video); + v4l2_device_unregister(&v4l2->v4l2_dev); + v4l2_ctrl_handler_free(&v4l2->ctrl_handler); + media_device_cleanup(&v4l2->media_dev); +} + /* Platform */ static irqreturn_t sun6i_csi_isr(int irq, void *private) @@ -959,7 +977,7 @@ static int sun6i_csi_probe(struct platform_device *platform_dev) if (ret) return ret; - ret = sun6i_csi_v4l2_init(csi_dev); + ret = sun6i_csi_v4l2_setup(csi_dev); if (ret) goto error_resources; From patchwork Fri Mar 11 14:34:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778118 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EE6BDC433FE for ; Fri, 11 Mar 2022 14:36:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349548AbiCKOhb (ORCPT ); Fri, 11 Mar 2022 09:37:31 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58842 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349471AbiCKOhQ (ORCPT ); Fri, 11 Mar 2022 09:37:16 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 54E501C8DB1; Fri, 11 Mar 2022 06:36:07 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 9D4A8240011; Fri, 11 Mar 2022 14:36:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009365; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=As8FHKuArtXUjJgsHBuiZbj8szWRRhUMbyHoELDxFPM=; b=f8aVmBcuox4O2nO+x+Tz63RTn0IXYKpF13PHIAn4xNt8AcHHMRoqPVHwpTg5cRfIgCpVG/ 7vwQmGFV/q029oble49/Q/kTmX2FWO4PTIoJVvAy9JLGTXoHbmZ/L/qIKlVEArtzorH3Mk xgGObAzYHQqq3iQcNPbJTu/ySehCCbSbXOYrvFZJitgxZE74hYR4p05RThHDdsJZ4PO6an xpomNbIZNvSErcKtqAGUYyqU4p/Gm5GxIAJQZ+UhoLPpidK4l9Bb9TELAZBlhTnrtJrMiX k7HLnIMb1SqWbLvzTknRPpJVj1lImqIwRnOQ+Dp9G8lG1swFFB9+HgY4DkYP2w== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni , Maxime Ripard Subject: [PATCH v3 10/46] media: sun6i-csi: Tidy up video code Date: Fri, 11 Mar 2022 15:34:56 +0100 Message-Id: <20220311143532.265091-11-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Some code cleanups, renames, variable lowerings and moving things around for better organization. No functional change intended. Signed-off-by: Paul Kocialkowski Reviewed-by: Maxime Ripard --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 4 +- .../platform/sunxi/sun6i-csi/sun6i_video.c | 508 ++++++++++-------- .../platform/sunxi/sun6i-csi/sun6i_video.h | 18 +- 3 files changed, 286 insertions(+), 244 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 1f694847ca65..6c031766a77a 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -595,7 +595,7 @@ static int sun6i_csi_link_entity(struct sun6i_csi_device *csi_dev, src_pad_index = ret; - sink = &csi_dev->video.vdev.entity; + sink = &csi_dev->video.video_dev.entity; sink_pad = &csi_dev->video.pad; dev_dbg(csi_dev->dev, "creating %s:%u -> %s:%u link\n", @@ -708,7 +708,7 @@ static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) /* Video */ - ret = sun6i_video_init(&csi_dev->video, csi_dev, SUN6I_CSI_NAME); + ret = sun6i_video_setup(&csi_dev->video, csi_dev); if (ret) goto error_v4l2_device; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index c152c0ceb6d5..427b23184a15 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -24,14 +24,34 @@ #define MAX_HEIGHT (4800) struct sun6i_csi_buffer { - struct vb2_v4l2_buffer vb; + struct vb2_v4l2_buffer v4l2_buffer; struct list_head list; dma_addr_t dma_addr; bool queued_to_csi; }; -static const u32 supported_pixformats[] = { +/* Helpers */ + +static struct v4l2_subdev * +sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad) +{ + struct media_pad *remote; + + remote = media_entity_remote_pad(&video->pad); + + if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) + return NULL; + + if (pad) + *pad = remote->index; + + return media_entity_to_v4l2_subdev(remote->entity); +} + +/* Format */ + +static const u32 sun6i_video_formats[] = { V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SGBRG8, V4L2_PIX_FMT_SGRBG8, @@ -61,77 +81,80 @@ static const u32 supported_pixformats[] = { V4L2_PIX_FMT_JPEG, }; -static bool is_pixformat_valid(unsigned int pixformat) +static bool sun6i_video_format_check(u32 format) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(supported_pixformats); i++) - if (supported_pixformats[i] == pixformat) + for (i = 0; i < ARRAY_SIZE(sun6i_video_formats); i++) + if (sun6i_video_formats[i] == format) return true; return false; } -static struct v4l2_subdev * -sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad) -{ - struct media_pad *remote; - - remote = media_entity_remote_pad(&video->pad); +/* Queue */ - if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) - return NULL; - - if (pad) - *pad = remote->index; - - return media_entity_to_v4l2_subdev(remote->entity); -} - -static int sun6i_video_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, - unsigned int *nplanes, +static int sun6i_video_queue_setup(struct vb2_queue *queue, + unsigned int *buffers_count, + unsigned int *planes_count, unsigned int sizes[], struct device *alloc_devs[]) { - struct sun6i_video *video = vb2_get_drv_priv(vq); - unsigned int size = video->fmt.fmt.pix.sizeimage; + struct sun6i_video *video = vb2_get_drv_priv(queue); + unsigned int size = video->format.fmt.pix.sizeimage; - if (*nplanes) + if (*planes_count) return sizes[0] < size ? -EINVAL : 0; - *nplanes = 1; + *planes_count = 1; sizes[0] = size; return 0; } -static int sun6i_video_buffer_prepare(struct vb2_buffer *vb) +static int sun6i_video_buffer_prepare(struct vb2_buffer *buffer) { - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct sun6i_csi_buffer *buf = - container_of(vbuf, struct sun6i_csi_buffer, vb); - struct sun6i_video *video = vb2_get_drv_priv(vb->vb2_queue); - unsigned long size = video->fmt.fmt.pix.sizeimage; - - if (vb2_plane_size(vb, 0) < size) { - v4l2_err(video->vdev.v4l2_dev, "buffer too small (%lu < %lu)\n", - vb2_plane_size(vb, 0), size); + struct sun6i_video *video = vb2_get_drv_priv(buffer->vb2_queue); + struct sun6i_csi_device *csi_dev = video->csi_dev; + struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; + struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer); + struct sun6i_csi_buffer *csi_buffer = + container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer); + unsigned long size = video->format.fmt.pix.sizeimage; + + if (vb2_plane_size(buffer, 0) < size) { + v4l2_err(v4l2_dev, "buffer too small (%lu < %lu)\n", + vb2_plane_size(buffer, 0), size); return -EINVAL; } - vb2_set_plane_payload(vb, 0, size); - - buf->dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + vb2_set_plane_payload(buffer, 0, size); - vbuf->field = video->fmt.fmt.pix.field; + csi_buffer->dma_addr = vb2_dma_contig_plane_dma_addr(buffer, 0); + v4l2_buffer->field = video->format.fmt.pix.field; return 0; } -static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) +static void sun6i_video_buffer_queue(struct vb2_buffer *buffer) +{ + struct sun6i_video *video = vb2_get_drv_priv(buffer->vb2_queue); + struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer); + struct sun6i_csi_buffer *csi_buffer = + container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer); + unsigned long flags; + + spin_lock_irqsave(&video->dma_queue_lock, flags); + csi_buffer->queued_to_csi = false; + list_add_tail(&csi_buffer->list, &video->dma_queue); + spin_unlock_irqrestore(&video->dma_queue_lock, flags); +} + +static int sun6i_video_start_streaming(struct vb2_queue *queue, + unsigned int count) { - struct sun6i_video *video = vb2_get_drv_priv(vq); + struct sun6i_video *video = vb2_get_drv_priv(queue); + struct video_device *video_dev = &video->video_dev; struct sun6i_csi_buffer *buf; struct sun6i_csi_buffer *next_buf; struct sun6i_csi_config config; @@ -141,30 +164,30 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) video->sequence = 0; - ret = media_pipeline_start(&video->vdev.entity, &video->vdev.pipe); + ret = media_pipeline_start(&video_dev->entity, &video_dev->pipe); if (ret < 0) - goto clear_dma_queue; + goto error_dma_queue_flush; if (video->mbus_code == 0) { ret = -EINVAL; - goto stop_media_pipeline; + goto error_media_pipeline; } subdev = sun6i_video_remote_subdev(video, NULL); if (!subdev) { ret = -EINVAL; - goto stop_media_pipeline; + goto error_media_pipeline; } - config.pixelformat = video->fmt.fmt.pix.pixelformat; + config.pixelformat = video->format.fmt.pix.pixelformat; config.code = video->mbus_code; - config.field = video->fmt.fmt.pix.field; - config.width = video->fmt.fmt.pix.width; - config.height = video->fmt.fmt.pix.height; + config.field = video->format.fmt.pix.field; + config.width = video->format.fmt.pix.width; + config.height = video->format.fmt.pix.height; ret = sun6i_csi_update_config(video->csi_dev, &config); if (ret < 0) - goto stop_media_pipeline; + goto error_media_pipeline; spin_lock_irqsave(&video->dma_queue_lock, flags); @@ -200,27 +223,30 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) ret = v4l2_subdev_call(subdev, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) - goto stop_csi_stream; + goto error_stream; return 0; -stop_csi_stream: +error_stream: sun6i_csi_set_stream(video->csi_dev, false); -stop_media_pipeline: - media_pipeline_stop(&video->vdev.entity); -clear_dma_queue: + +error_media_pipeline: + media_pipeline_stop(&video_dev->entity); + +error_dma_queue_flush: spin_lock_irqsave(&video->dma_queue_lock, flags); list_for_each_entry(buf, &video->dma_queue, list) - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); + vb2_buffer_done(&buf->v4l2_buffer.vb2_buf, + VB2_BUF_STATE_QUEUED); INIT_LIST_HEAD(&video->dma_queue); spin_unlock_irqrestore(&video->dma_queue_lock, flags); return ret; } -static void sun6i_video_stop_streaming(struct vb2_queue *vq) +static void sun6i_video_stop_streaming(struct vb2_queue *queue) { - struct sun6i_video *video = vb2_get_drv_priv(vq); + struct sun6i_video *video = vb2_get_drv_priv(queue); struct v4l2_subdev *subdev; unsigned long flags; struct sun6i_csi_buffer *buf; @@ -231,35 +257,21 @@ static void sun6i_video_stop_streaming(struct vb2_queue *vq) sun6i_csi_set_stream(video->csi_dev, false); - media_pipeline_stop(&video->vdev.entity); + media_pipeline_stop(&video->video_dev.entity); /* Release all active buffers */ spin_lock_irqsave(&video->dma_queue_lock, flags); list_for_each_entry(buf, &video->dma_queue, list) - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + vb2_buffer_done(&buf->v4l2_buffer.vb2_buf, VB2_BUF_STATE_ERROR); INIT_LIST_HEAD(&video->dma_queue); spin_unlock_irqrestore(&video->dma_queue_lock, flags); } -static void sun6i_video_buffer_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct sun6i_csi_buffer *buf = - container_of(vbuf, struct sun6i_csi_buffer, vb); - struct sun6i_video *video = vb2_get_drv_priv(vb->vb2_queue); - unsigned long flags; - - spin_lock_irqsave(&video->dma_queue_lock, flags); - buf->queued_to_csi = false; - list_add_tail(&buf->list, &video->dma_queue); - spin_unlock_irqrestore(&video->dma_queue_lock, flags); -} - void sun6i_video_frame_done(struct sun6i_video *video) { struct sun6i_csi_buffer *buf; struct sun6i_csi_buffer *next_buf; - struct vb2_v4l2_buffer *vbuf; + struct vb2_v4l2_buffer *v4l2_buffer; spin_lock(&video->dma_queue_lock); @@ -267,7 +279,7 @@ void sun6i_video_frame_done(struct sun6i_video *video) struct sun6i_csi_buffer, list); if (list_is_last(&buf->list, &video->dma_queue)) { dev_dbg(video->csi_dev->dev, "Frame dropped!\n"); - goto unlock; + goto complete; } next_buf = list_next_entry(buf, list); @@ -280,14 +292,14 @@ void sun6i_video_frame_done(struct sun6i_video *video) next_buf->queued_to_csi = true; sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr); dev_dbg(video->csi_dev->dev, "Frame dropped!\n"); - goto unlock; + goto complete; } list_del(&buf->list); - vbuf = &buf->vb; - vbuf->vb2_buf.timestamp = ktime_get_ns(); - vbuf->sequence = video->sequence; - vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); + v4l2_buffer = &buf->v4l2_buffer; + v4l2_buffer->vb2_buf.timestamp = ktime_get_ns(); + v4l2_buffer->sequence = video->sequence; + vb2_buffer_done(&v4l2_buffer->vb2_buf, VB2_BUF_STATE_DONE); /* Prepare buffer for next frame but one. */ if (!list_is_last(&next_buf->list, &video->dma_queue)) { @@ -298,161 +310,169 @@ void sun6i_video_frame_done(struct sun6i_video *video) dev_dbg(video->csi_dev->dev, "Next frame will be dropped!\n"); } -unlock: +complete: video->sequence++; spin_unlock(&video->dma_queue_lock); } -static const struct vb2_ops sun6i_csi_vb2_ops = { +static const struct vb2_ops sun6i_video_queue_ops = { .queue_setup = sun6i_video_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = sun6i_video_buffer_prepare, + .buf_queue = sun6i_video_buffer_queue, .start_streaming = sun6i_video_start_streaming, .stop_streaming = sun6i_video_stop_streaming, - .buf_queue = sun6i_video_buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) +/* V4L2 Device */ + +static int sun6i_video_querycap(struct file *file, void *private, + struct v4l2_capability *capability) { struct sun6i_video *video = video_drvdata(file); + struct sun6i_csi_device *csi_dev = video->csi_dev; + struct video_device *video_dev = &video->video_dev; - strscpy(cap->driver, "sun6i-video", sizeof(cap->driver)); - strscpy(cap->card, video->vdev.name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - video->csi_dev->dev->of_node->name); + strscpy(capability->driver, SUN6I_CSI_NAME, sizeof(capability->driver)); + strscpy(capability->card, video_dev->name, sizeof(capability->card)); + snprintf(capability->bus_info, sizeof(capability->bus_info), + "platform:%s", dev_name(csi_dev->dev)); return 0; } -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int sun6i_video_enum_fmt(struct file *file, void *private, + struct v4l2_fmtdesc *fmtdesc) { - u32 index = f->index; + u32 index = fmtdesc->index; - if (index >= ARRAY_SIZE(supported_pixformats)) + if (index >= ARRAY_SIZE(sun6i_video_formats)) return -EINVAL; - f->pixelformat = supported_pixformats[index]; + fmtdesc->pixelformat = sun6i_video_formats[index]; return 0; } -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) +static int sun6i_video_g_fmt(struct file *file, void *private, + struct v4l2_format *format) { struct sun6i_video *video = video_drvdata(file); - *fmt = video->fmt; + *format = video->format; return 0; } -static int sun6i_video_try_fmt(struct sun6i_video *video, - struct v4l2_format *f) +static int sun6i_video_format_try(struct sun6i_video *video, + struct v4l2_format *format) { - struct v4l2_pix_format *pixfmt = &f->fmt.pix; + struct v4l2_pix_format *pix_format = &format->fmt.pix; int bpp; - if (!is_pixformat_valid(pixfmt->pixelformat)) - pixfmt->pixelformat = supported_pixformats[0]; + if (!sun6i_video_format_check(pix_format->pixelformat)) + pix_format->pixelformat = sun6i_video_formats[0]; - v4l_bound_align_image(&pixfmt->width, MIN_WIDTH, MAX_WIDTH, 1, - &pixfmt->height, MIN_HEIGHT, MAX_WIDTH, 1, 1); + v4l_bound_align_image(&pix_format->width, MIN_WIDTH, MAX_WIDTH, 1, + &pix_format->height, MIN_HEIGHT, MAX_WIDTH, 1, 1); - bpp = sun6i_csi_get_bpp(pixfmt->pixelformat); - pixfmt->bytesperline = (pixfmt->width * bpp) >> 3; - pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; + bpp = sun6i_csi_get_bpp(pix_format->pixelformat); + pix_format->bytesperline = (pix_format->width * bpp) >> 3; + pix_format->sizeimage = pix_format->bytesperline * pix_format->height; - if (pixfmt->field == V4L2_FIELD_ANY) - pixfmt->field = V4L2_FIELD_NONE; + if (pix_format->field == V4L2_FIELD_ANY) + pix_format->field = V4L2_FIELD_NONE; - pixfmt->colorspace = V4L2_COLORSPACE_RAW; - pixfmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - pixfmt->quantization = V4L2_QUANTIZATION_DEFAULT; - pixfmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; + pix_format->colorspace = V4L2_COLORSPACE_RAW; + pix_format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + pix_format->quantization = V4L2_QUANTIZATION_DEFAULT; + pix_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; return 0; } -static int sun6i_video_set_fmt(struct sun6i_video *video, struct v4l2_format *f) +static int sun6i_video_format_set(struct sun6i_video *video, + struct v4l2_format *format) { int ret; - ret = sun6i_video_try_fmt(video, f); + ret = sun6i_video_format_try(video, format); if (ret) return ret; - video->fmt = *f; + video->format = *format; return 0; } -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int sun6i_video_s_fmt(struct file *file, void *private, + struct v4l2_format *format) { struct sun6i_video *video = video_drvdata(file); - if (vb2_is_busy(&video->vb2_vidq)) + if (vb2_is_busy(&video->queue)) return -EBUSY; - return sun6i_video_set_fmt(video, f); + return sun6i_video_format_set(video, format); } -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int sun6i_video_try_fmt(struct file *file, void *private, + struct v4l2_format *format) { struct sun6i_video *video = video_drvdata(file); - return sun6i_video_try_fmt(video, f); + return sun6i_video_format_try(video, format); } -static int vidioc_enum_input(struct file *file, void *fh, - struct v4l2_input *inp) +static int sun6i_video_enum_input(struct file *file, void *private, + struct v4l2_input *input) { - if (inp->index != 0) + if (input->index != 0) return -EINVAL; - strscpy(inp->name, "camera", sizeof(inp->name)); - inp->type = V4L2_INPUT_TYPE_CAMERA; + input->type = V4L2_INPUT_TYPE_CAMERA; + strscpy(input->name, "Camera", sizeof(input->name)); return 0; } -static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) +static int sun6i_video_g_input(struct file *file, void *private, + unsigned int *index) { - *i = 0; + *index = 0; return 0; } -static int vidioc_s_input(struct file *file, void *fh, unsigned int i) +static int sun6i_video_s_input(struct file *file, void *private, + unsigned int index) { - if (i != 0) + if (index != 0) return -EINVAL; return 0; } static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_querycap = sun6i_video_querycap, + + .vidioc_enum_fmt_vid_cap = sun6i_video_enum_fmt, + .vidioc_g_fmt_vid_cap = sun6i_video_g_fmt, + .vidioc_s_fmt_vid_cap = sun6i_video_s_fmt, + .vidioc_try_fmt_vid_cap = sun6i_video_try_fmt, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_input = vidioc_g_input, + .vidioc_enum_input = sun6i_video_enum_input, + .vidioc_g_input = sun6i_video_g_input, + .vidioc_s_input = sun6i_video_s_input, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_qbuf = vb2_ioctl_qbuf, .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, @@ -461,9 +481,8 @@ static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -/* ----------------------------------------------------------------------------- - * V4L2 file operations - */ +/* V4L2 File */ + static int sun6i_video_open(struct file *file) { struct sun6i_video *video = video_drvdata(file); @@ -474,44 +493,46 @@ static int sun6i_video_open(struct file *file) ret = v4l2_fh_open(file); if (ret < 0) - goto unlock; + goto error_lock; - ret = v4l2_pipeline_pm_get(&video->vdev.entity); + ret = v4l2_pipeline_pm_get(&video->video_dev.entity); if (ret < 0) - goto fh_release; - - /* check if already powered */ - if (!v4l2_fh_is_singular_file(file)) - goto unlock; + goto error_v4l2_fh; - ret = sun6i_csi_set_power(video->csi_dev, true); - if (ret < 0) - goto fh_release; + /* Power on at first open. */ + if (v4l2_fh_is_singular_file(file)) { + ret = sun6i_csi_set_power(video->csi_dev, true); + if (ret < 0) + goto error_v4l2_fh; + } mutex_unlock(&video->lock); + return 0; -fh_release: +error_v4l2_fh: v4l2_fh_release(file); -unlock: + +error_lock: mutex_unlock(&video->lock); + return ret; } static int sun6i_video_close(struct file *file) { struct sun6i_video *video = video_drvdata(file); - bool last_fh; + bool last_close; mutex_lock(&video->lock); - last_fh = v4l2_fh_is_singular_file(file); + last_close = v4l2_fh_is_singular_file(file); _vb2_fop_release(file, NULL); + v4l2_pipeline_pm_put(&video->video_dev.entity); - v4l2_pipeline_pm_put(&video->vdev.entity); - - if (last_fh) + /* Power off at last close. */ + if (last_close) sun6i_csi_set_power(video->csi_dev, false); mutex_unlock(&video->lock); @@ -528,9 +549,8 @@ static const struct v4l2_file_operations sun6i_video_fops = { .poll = vb2_fop_poll }; -/* ----------------------------------------------------------------------------- - * Media Operations - */ +/* Media Entity */ + static int sun6i_video_link_validate_get_format(struct media_pad *pad, struct v4l2_subdev_format *fmt) { @@ -567,20 +587,20 @@ static int sun6i_video_link_validate(struct media_link *link) return ret; if (!sun6i_csi_is_format_supported(video->csi_dev, - video->fmt.fmt.pix.pixelformat, + video->format.fmt.pix.pixelformat, source_fmt.format.code)) { dev_err(video->csi_dev->dev, "Unsupported pixformat: 0x%x with mbus code: 0x%x!\n", - video->fmt.fmt.pix.pixelformat, + video->format.fmt.pix.pixelformat, source_fmt.format.code); return -EPIPE; } - if (source_fmt.format.width != video->fmt.fmt.pix.width || - source_fmt.format.height != video->fmt.fmt.pix.height) { + if (source_fmt.format.width != video->format.fmt.pix.width || + source_fmt.format.height != video->format.fmt.pix.height) { dev_err(video->csi_dev->dev, "Wrong width or height %ux%u (%ux%u expected)\n", - video->fmt.fmt.pix.width, video->fmt.fmt.pix.height, + video->format.fmt.pix.width, video->format.fmt.pix.height, source_fmt.format.width, source_fmt.format.height); return -EPIPE; } @@ -594,90 +614,112 @@ static const struct media_entity_operations sun6i_video_media_ops = { .link_validate = sun6i_video_link_validate }; -int sun6i_video_init(struct sun6i_video *video, - struct sun6i_csi_device *csi_dev, const char *name) +/* Video */ + +int sun6i_video_setup(struct sun6i_video *video, + struct sun6i_csi_device *csi_dev) { - struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; - struct video_device *vdev = &video->vdev; - struct vb2_queue *vidq = &video->vb2_vidq; - struct v4l2_format fmt = { 0 }; + struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; + struct video_device *video_dev = &video->video_dev; + struct vb2_queue *queue = &video->queue; + struct media_pad *pad = &video->pad; + struct v4l2_format format = { 0 }; + struct v4l2_pix_format *pix_format = &format.fmt.pix; int ret; video->csi_dev = csi_dev; - /* Initialize the media entity... */ - video->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; - vdev->entity.ops = &sun6i_video_media_ops; - ret = media_entity_pads_init(&vdev->entity, 1, &video->pad); + /* Media Entity */ + + video_dev->entity.ops = &sun6i_video_media_ops; + + /* Media Pad */ + + pad->flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; + + ret = media_entity_pads_init(&video_dev->entity, 1, pad); if (ret < 0) return ret; - mutex_init(&video->lock); + /* DMA queue */ INIT_LIST_HEAD(&video->dma_queue); spin_lock_init(&video->dma_queue_lock); video->sequence = 0; - /* Setup default format */ - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt.fmt.pix.pixelformat = supported_pixformats[0]; - fmt.fmt.pix.width = 1280; - fmt.fmt.pix.height = 720; - fmt.fmt.pix.field = V4L2_FIELD_NONE; - sun6i_video_set_fmt(video, &fmt); - - /* Initialize videobuf2 queue */ - vidq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - vidq->io_modes = VB2_MMAP | VB2_DMABUF; - vidq->drv_priv = video; - vidq->buf_struct_size = sizeof(struct sun6i_csi_buffer); - vidq->ops = &sun6i_csi_vb2_ops; - vidq->mem_ops = &vb2_dma_contig_memops; - vidq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - vidq->lock = &video->lock; - /* Make sure non-dropped frame */ - vidq->min_buffers_needed = 3; - vidq->dev = csi_dev->dev; - - ret = vb2_queue_init(vidq); + /* Queue */ + + mutex_init(&video->lock); + + queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + queue->io_modes = VB2_MMAP | VB2_DMABUF; + queue->buf_struct_size = sizeof(struct sun6i_csi_buffer); + queue->ops = &sun6i_video_queue_ops; + queue->mem_ops = &vb2_dma_contig_memops; + queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + queue->lock = &video->lock; + queue->dev = csi_dev->dev; + queue->drv_priv = video; + + /* Make sure non-dropped frame. */ + queue->min_buffers_needed = 3; + + ret = vb2_queue_init(queue); if (ret) { - v4l2_err(&v4l2->v4l2_dev, "vb2_queue_init failed: %d\n", - ret); - goto clean_entity; + v4l2_err(v4l2_dev, "failed to initialize vb2 queue: %d\n", ret); + goto error_media_entity; } - /* Register video device */ - strscpy(vdev->name, name, sizeof(vdev->name)); - vdev->release = video_device_release_empty; - vdev->fops = &sun6i_video_fops; - vdev->ioctl_ops = &sun6i_video_ioctl_ops; - vdev->vfl_type = VFL_TYPE_VIDEO; - vdev->vfl_dir = VFL_DIR_RX; - vdev->v4l2_dev = &v4l2->v4l2_dev; - vdev->queue = vidq; - vdev->lock = &video->lock; - vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; - video_set_drvdata(vdev, video); - - ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + /* V4L2 Format */ + + format.type = queue->type; + pix_format->pixelformat = sun6i_video_formats[0]; + pix_format->width = 1280; + pix_format->height = 720; + pix_format->field = V4L2_FIELD_NONE; + + sun6i_video_format_set(video, &format); + + /* Video Device */ + + strscpy(video_dev->name, SUN6I_CSI_NAME, sizeof(video_dev->name)); + video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + video_dev->vfl_dir = VFL_DIR_RX; + video_dev->release = video_device_release_empty; + video_dev->fops = &sun6i_video_fops; + video_dev->ioctl_ops = &sun6i_video_ioctl_ops; + video_dev->v4l2_dev = v4l2_dev; + video_dev->queue = queue; + video_dev->lock = &video->lock; + + video_set_drvdata(video_dev, video); + + ret = video_register_device(video_dev, VFL_TYPE_VIDEO, -1); if (ret < 0) { - v4l2_err(&v4l2->v4l2_dev, - "video_register_device failed: %d\n", ret); - goto clean_entity; + v4l2_err(v4l2_dev, "failed to register video device: %d\n", + ret); + goto error_media_entity; } + v4l2_info(v4l2_dev, "device %s registered as %s\n", video_dev->name, + video_device_node_name(video_dev)); + return 0; -clean_entity: - media_entity_cleanup(&video->vdev.entity); +error_media_entity: + media_entity_cleanup(&video_dev->entity); + mutex_destroy(&video->lock); + return ret; } void sun6i_video_cleanup(struct sun6i_video *video) { - vb2_video_unregister_device(&video->vdev); - media_entity_cleanup(&video->vdev.entity); + struct video_device *video_dev = &video->video_dev; + + vb2_video_unregister_device(video_dev); + media_entity_cleanup(&video_dev->entity); mutex_destroy(&video->lock); } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h index 30e37ee0d07f..7864f062d05b 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h @@ -15,22 +15,22 @@ struct sun6i_csi_device; struct sun6i_video { struct sun6i_csi_device *csi_dev; - struct video_device vdev; - struct media_pad pad; - struct mutex lock; + struct video_device video_dev; + struct vb2_queue queue; + struct mutex lock; /* Queue lock. */ + struct media_pad pad; - struct vb2_queue vb2_vidq; - spinlock_t dma_queue_lock; struct list_head dma_queue; + spinlock_t dma_queue_lock; /* DMA queue lock. */ - unsigned int sequence; - struct v4l2_format fmt; + struct v4l2_format format; u32 mbus_code; + unsigned int sequence; }; -int sun6i_video_init(struct sun6i_video *video, - struct sun6i_csi_device *csi_dev, const char *name); +int sun6i_video_setup(struct sun6i_video *video, + struct sun6i_csi_device *csi_dev); void sun6i_video_cleanup(struct sun6i_video *video); void sun6i_video_frame_done(struct sun6i_video *video); From patchwork Fri Mar 11 14:34:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778119 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 35282C4332F for ; Fri, 11 Mar 2022 14:36:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349558AbiCKOhc (ORCPT ); Fri, 11 Mar 2022 09:37:32 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58896 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349475AbiCKOhQ (ORCPT ); Fri, 11 Mar 2022 09:37:16 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6C7661C8DBF; Fri, 11 Mar 2022 06:36:08 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id EE8EF240002; Fri, 11 Mar 2022 14:36:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009367; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=bsBwGN1uf0jcNWm9wWfOkpdN1on6MEqkVQujmTVNRO0=; b=DnYb0X0bUo+cnkpY5ntO/Rir9o9KYCgbghuJRchQLDN+UqB+Fw8T/6s++a1ZIdresI2srl Lmm8KobsY+nKd2QmzmaIf5KpXVrgtMCRnYeVIat7kfQA8iWnKWuAwZFU61d8av7Ykds+m3 FEjj4FI3LzEyZurZOXiOWfmdKc66h8yf74+pC6QmTbOZ0S9quSD+twsB1puU2RzVsf6B55 7oHYWeutOlUauurJzyc0VoZNJx7PS+qNopXChj9cKL/davOqjTCQ1H2LnLpA81/4+YBMa2 TY947XWcUrQ7hFVYmRgwsmq8b5JvGekniwmk1IG56aCWlrWJvV9l5TWQc4oLgQ== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni , Maxime Ripard Subject: [PATCH v3 11/46] media: sun6i-csi: Pass and store csi device directly in video code Date: Fri, 11 Mar 2022 15:34:57 +0100 Message-Id: <20220311143532.265091-12-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org The video structure is part of the main csi device structure, so pass pointers to that top-level structure directly. This makes it easier to navigate and access other elements. No functional change intended. Signed-off-by: Paul Kocialkowski Reviewed-by: Maxime Ripard --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 8 +- .../platform/sunxi/sun6i-csi/sun6i_video.c | 91 ++++++++++--------- .../platform/sunxi/sun6i-csi/sun6i_video.h | 9 +- 3 files changed, 57 insertions(+), 51 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 6c031766a77a..99b2cf5fe184 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -708,7 +708,7 @@ static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) /* Video */ - ret = sun6i_video_setup(&csi_dev->video, csi_dev); + ret = sun6i_video_setup(csi_dev); if (ret) goto error_v4l2_device; @@ -737,7 +737,7 @@ static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) v4l2_async_nf_cleanup(notifier); error_video: - sun6i_video_cleanup(&csi_dev->video); + sun6i_video_cleanup(csi_dev); error_v4l2_device: v4l2_device_unregister(&v4l2->v4l2_dev); @@ -758,7 +758,7 @@ static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev) media_device_unregister(&v4l2->media_dev); v4l2_async_nf_unregister(&v4l2->notifier); v4l2_async_nf_cleanup(&v4l2->notifier); - sun6i_video_cleanup(&csi_dev->video); + sun6i_video_cleanup(csi_dev); v4l2_device_unregister(&v4l2->v4l2_dev); v4l2_ctrl_handler_free(&v4l2->ctrl_handler); media_device_cleanup(&v4l2->media_dev); @@ -789,7 +789,7 @@ static irqreturn_t sun6i_csi_isr(int irq, void *private) } if (status & CSI_CH_INT_STA_FD_PD) - sun6i_video_frame_done(&csi_dev->video); + sun6i_video_frame_done(csi_dev); regmap_write(regmap, CSI_CH_INT_STA_REG, status); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index 427b23184a15..178dddb0eaf1 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -100,7 +100,8 @@ static int sun6i_video_queue_setup(struct vb2_queue *queue, unsigned int sizes[], struct device *alloc_devs[]) { - struct sun6i_video *video = vb2_get_drv_priv(queue); + struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); + struct sun6i_video *video = &csi_dev->video; unsigned int size = video->format.fmt.pix.sizeimage; if (*planes_count) @@ -114,8 +115,8 @@ static int sun6i_video_queue_setup(struct vb2_queue *queue, static int sun6i_video_buffer_prepare(struct vb2_buffer *buffer) { - struct sun6i_video *video = vb2_get_drv_priv(buffer->vb2_queue); - struct sun6i_csi_device *csi_dev = video->csi_dev; + struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue); + struct sun6i_video *video = &csi_dev->video; struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer); struct sun6i_csi_buffer *csi_buffer = @@ -138,7 +139,8 @@ static int sun6i_video_buffer_prepare(struct vb2_buffer *buffer) static void sun6i_video_buffer_queue(struct vb2_buffer *buffer) { - struct sun6i_video *video = vb2_get_drv_priv(buffer->vb2_queue); + struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue); + struct sun6i_video *video = &csi_dev->video; struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer); struct sun6i_csi_buffer *csi_buffer = container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer); @@ -153,7 +155,8 @@ static void sun6i_video_buffer_queue(struct vb2_buffer *buffer) static int sun6i_video_start_streaming(struct vb2_queue *queue, unsigned int count) { - struct sun6i_video *video = vb2_get_drv_priv(queue); + struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); + struct sun6i_video *video = &csi_dev->video; struct video_device *video_dev = &video->video_dev; struct sun6i_csi_buffer *buf; struct sun6i_csi_buffer *next_buf; @@ -185,7 +188,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue, config.width = video->format.fmt.pix.width; config.height = video->format.fmt.pix.height; - ret = sun6i_csi_update_config(video->csi_dev, &config); + ret = sun6i_csi_update_config(csi_dev, &config); if (ret < 0) goto error_media_pipeline; @@ -194,9 +197,9 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue, buf = list_first_entry(&video->dma_queue, struct sun6i_csi_buffer, list); buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi_dev, buf->dma_addr); + sun6i_csi_update_buf_addr(csi_dev, buf->dma_addr); - sun6i_csi_set_stream(video->csi_dev, true); + sun6i_csi_set_stream(csi_dev, true); /* * CSI will lookup the next dma buffer for next frame before the @@ -217,7 +220,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue, */ next_buf = list_next_entry(buf, list); next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr); + sun6i_csi_update_buf_addr(csi_dev, next_buf->dma_addr); spin_unlock_irqrestore(&video->dma_queue_lock, flags); @@ -228,7 +231,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue, return 0; error_stream: - sun6i_csi_set_stream(video->csi_dev, false); + sun6i_csi_set_stream(csi_dev, false); error_media_pipeline: media_pipeline_stop(&video_dev->entity); @@ -246,7 +249,8 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue, static void sun6i_video_stop_streaming(struct vb2_queue *queue) { - struct sun6i_video *video = vb2_get_drv_priv(queue); + struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); + struct sun6i_video *video = &csi_dev->video; struct v4l2_subdev *subdev; unsigned long flags; struct sun6i_csi_buffer *buf; @@ -255,7 +259,7 @@ static void sun6i_video_stop_streaming(struct vb2_queue *queue) if (subdev) v4l2_subdev_call(subdev, video, s_stream, 0); - sun6i_csi_set_stream(video->csi_dev, false); + sun6i_csi_set_stream(csi_dev, false); media_pipeline_stop(&video->video_dev.entity); @@ -267,8 +271,9 @@ static void sun6i_video_stop_streaming(struct vb2_queue *queue) spin_unlock_irqrestore(&video->dma_queue_lock, flags); } -void sun6i_video_frame_done(struct sun6i_video *video) +void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev) { + struct sun6i_video *video = &csi_dev->video; struct sun6i_csi_buffer *buf; struct sun6i_csi_buffer *next_buf; struct vb2_v4l2_buffer *v4l2_buffer; @@ -278,7 +283,7 @@ void sun6i_video_frame_done(struct sun6i_video *video) buf = list_first_entry(&video->dma_queue, struct sun6i_csi_buffer, list); if (list_is_last(&buf->list, &video->dma_queue)) { - dev_dbg(video->csi_dev->dev, "Frame dropped!\n"); + dev_dbg(csi_dev->dev, "Frame dropped!\n"); goto complete; } @@ -290,8 +295,8 @@ void sun6i_video_frame_done(struct sun6i_video *video) */ if (!next_buf->queued_to_csi) { next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr); - dev_dbg(video->csi_dev->dev, "Frame dropped!\n"); + sun6i_csi_update_buf_addr(csi_dev, next_buf->dma_addr); + dev_dbg(csi_dev->dev, "Frame dropped!\n"); goto complete; } @@ -305,9 +310,9 @@ void sun6i_video_frame_done(struct sun6i_video *video) if (!list_is_last(&next_buf->list, &video->dma_queue)) { next_buf = list_next_entry(next_buf, list); next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr); + sun6i_csi_update_buf_addr(csi_dev, next_buf->dma_addr); } else { - dev_dbg(video->csi_dev->dev, "Next frame will be dropped!\n"); + dev_dbg(csi_dev->dev, "Next frame will be dropped!\n"); } complete: @@ -330,9 +335,8 @@ static const struct vb2_ops sun6i_video_queue_ops = { static int sun6i_video_querycap(struct file *file, void *private, struct v4l2_capability *capability) { - struct sun6i_video *video = video_drvdata(file); - struct sun6i_csi_device *csi_dev = video->csi_dev; - struct video_device *video_dev = &video->video_dev; + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct video_device *video_dev = &csi_dev->video.video_dev; strscpy(capability->driver, SUN6I_CSI_NAME, sizeof(capability->driver)); strscpy(capability->card, video_dev->name, sizeof(capability->card)); @@ -358,7 +362,8 @@ static int sun6i_video_enum_fmt(struct file *file, void *private, static int sun6i_video_g_fmt(struct file *file, void *private, struct v4l2_format *format) { - struct sun6i_video *video = video_drvdata(file); + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct sun6i_video *video = &csi_dev->video; *format = video->format; @@ -409,7 +414,8 @@ static int sun6i_video_format_set(struct sun6i_video *video, static int sun6i_video_s_fmt(struct file *file, void *private, struct v4l2_format *format) { - struct sun6i_video *video = video_drvdata(file); + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct sun6i_video *video = &csi_dev->video; if (vb2_is_busy(&video->queue)) return -EBUSY; @@ -420,7 +426,8 @@ static int sun6i_video_s_fmt(struct file *file, void *private, static int sun6i_video_try_fmt(struct file *file, void *private, struct v4l2_format *format) { - struct sun6i_video *video = video_drvdata(file); + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct sun6i_video *video = &csi_dev->video; return sun6i_video_format_try(video, format); } @@ -485,7 +492,8 @@ static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = { static int sun6i_video_open(struct file *file) { - struct sun6i_video *video = video_drvdata(file); + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct sun6i_video *video = &csi_dev->video; int ret = 0; if (mutex_lock_interruptible(&video->lock)) @@ -501,7 +509,7 @@ static int sun6i_video_open(struct file *file) /* Power on at first open. */ if (v4l2_fh_is_singular_file(file)) { - ret = sun6i_csi_set_power(video->csi_dev, true); + ret = sun6i_csi_set_power(csi_dev, true); if (ret < 0) goto error_v4l2_fh; } @@ -521,7 +529,8 @@ static int sun6i_video_open(struct file *file) static int sun6i_video_close(struct file *file) { - struct sun6i_video *video = video_drvdata(file); + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct sun6i_video *video = &csi_dev->video; bool last_close; mutex_lock(&video->lock); @@ -533,7 +542,7 @@ static int sun6i_video_close(struct file *file) /* Power off at last close. */ if (last_close) - sun6i_csi_set_power(video->csi_dev, false); + sun6i_csi_set_power(csi_dev, false); mutex_unlock(&video->lock); @@ -570,15 +579,16 @@ static int sun6i_video_link_validate(struct media_link *link) { struct video_device *vdev = container_of(link->sink->entity, struct video_device, entity); - struct sun6i_video *video = video_get_drvdata(vdev); + struct sun6i_csi_device *csi_dev = video_get_drvdata(vdev); + struct sun6i_video *video = &csi_dev->video; struct v4l2_subdev_format source_fmt; int ret; video->mbus_code = 0; if (!media_entity_remote_pad(link->sink->entity->pads)) { - dev_info(video->csi_dev->dev, - "video node %s pad not connected\n", vdev->name); + dev_info(csi_dev->dev, "video node %s pad not connected\n", + vdev->name); return -ENOLINK; } @@ -586,10 +596,10 @@ static int sun6i_video_link_validate(struct media_link *link) if (ret < 0) return ret; - if (!sun6i_csi_is_format_supported(video->csi_dev, + if (!sun6i_csi_is_format_supported(csi_dev, video->format.fmt.pix.pixelformat, source_fmt.format.code)) { - dev_err(video->csi_dev->dev, + dev_err(csi_dev->dev, "Unsupported pixformat: 0x%x with mbus code: 0x%x!\n", video->format.fmt.pix.pixelformat, source_fmt.format.code); @@ -598,7 +608,7 @@ static int sun6i_video_link_validate(struct media_link *link) if (source_fmt.format.width != video->format.fmt.pix.width || source_fmt.format.height != video->format.fmt.pix.height) { - dev_err(video->csi_dev->dev, + dev_err(csi_dev->dev, "Wrong width or height %ux%u (%ux%u expected)\n", video->format.fmt.pix.width, video->format.fmt.pix.height, source_fmt.format.width, source_fmt.format.height); @@ -616,9 +626,9 @@ static const struct media_entity_operations sun6i_video_media_ops = { /* Video */ -int sun6i_video_setup(struct sun6i_video *video, - struct sun6i_csi_device *csi_dev) +int sun6i_video_setup(struct sun6i_csi_device *csi_dev) { + struct sun6i_video *video = &csi_dev->video; struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; struct video_device *video_dev = &video->video_dev; struct vb2_queue *queue = &video->queue; @@ -627,8 +637,6 @@ int sun6i_video_setup(struct sun6i_video *video, struct v4l2_pix_format *pix_format = &format.fmt.pix; int ret; - video->csi_dev = csi_dev; - /* Media Entity */ video_dev->entity.ops = &sun6i_video_media_ops; @@ -660,7 +668,7 @@ int sun6i_video_setup(struct sun6i_video *video, queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; queue->lock = &video->lock; queue->dev = csi_dev->dev; - queue->drv_priv = video; + queue->drv_priv = csi_dev; /* Make sure non-dropped frame. */ queue->min_buffers_needed = 3; @@ -693,7 +701,7 @@ int sun6i_video_setup(struct sun6i_video *video, video_dev->queue = queue; video_dev->lock = &video->lock; - video_set_drvdata(video_dev, video); + video_set_drvdata(video_dev, csi_dev); ret = video_register_device(video_dev, VFL_TYPE_VIDEO, -1); if (ret < 0) { @@ -715,8 +723,9 @@ int sun6i_video_setup(struct sun6i_video *video, return ret; } -void sun6i_video_cleanup(struct sun6i_video *video) +void sun6i_video_cleanup(struct sun6i_csi_device *csi_dev) { + struct sun6i_video *video = &csi_dev->video; struct video_device *video_dev = &video->video_dev; vb2_video_unregister_device(video_dev); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h index 7864f062d05b..a917d2da6deb 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h @@ -14,8 +14,6 @@ struct sun6i_csi_device; struct sun6i_video { - struct sun6i_csi_device *csi_dev; - struct video_device video_dev; struct vb2_queue queue; struct mutex lock; /* Queue lock. */ @@ -29,10 +27,9 @@ struct sun6i_video { unsigned int sequence; }; -int sun6i_video_setup(struct sun6i_video *video, - struct sun6i_csi_device *csi_dev); -void sun6i_video_cleanup(struct sun6i_video *video); +int sun6i_video_setup(struct sun6i_csi_device *csi_dev); +void sun6i_video_cleanup(struct sun6i_csi_device *csi_dev); -void sun6i_video_frame_done(struct sun6i_video *video); +void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev); #endif /* __SUN6I_VIDEO_H__ */ From patchwork Fri Mar 11 14:34:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778145 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C24A2C433F5 for ; Fri, 11 Mar 2022 14:37:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349594AbiCKOiT (ORCPT ); Fri, 11 Mar 2022 09:38:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58848 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349493AbiCKOhX (ORCPT ); Fri, 11 Mar 2022 09:37:23 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2D42A1C9455; Fri, 11 Mar 2022 06:36:09 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 36CEE240006; Fri, 11 Mar 2022 14:36:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009368; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pEx0KTi/PkAn0HHoRLYFjHtkOB03J6H8SvSr1IBFJQw=; b=MVD4chTJZjRe+ve9BqmHAImlfQaDD+mVGgcucaCm4VqRDPOXhPVDd8U1X1SFSn292sZs7d 8wH5Zyq6St+etn7bb3T5kuls39kAp9bxLrKFUBp5Lk+E5WoWUJg8+aphCHbl6kfWQ0y7NA CBt97+zzHHg++ObPk+c/etaIDlXF3CswXtcJffDg/j2v8Ga909EvJwvo+EvrwFqaOuZ+CR tf4uEyUMJ7qub3sEJ9/Z6wY8c0yVYxcOCXEVlQ56E+hPEVDSZXExHD0PpL2C8l8CbU20Ju LAKt1fyt76c9JTVdOv2MSg+TnFm2WiBtceOq41YKC80+e0YdgV/qcAza2txxMw== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 12/46] media: sun6i-csi: Register the media device after creation Date: Fri, 11 Mar 2022 15:34:58 +0100 Message-Id: <20220311143532.265091-13-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org There is no particular need to register the media device in the subdev notify complete callback. Register it in the v4l2 code instead where it's more in-context. Signed-off-by: Paul Kocialkowski --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 99b2cf5fe184..38e41e0c8a3c 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -638,7 +638,7 @@ static int sun6i_subdev_notify_complete(struct v4l2_async_notifier *notifier) if (ret < 0) return ret; - return media_device_register(&v4l2->media_dev); + return 0; } static const struct v4l2_async_notifier_operations sun6i_csi_async_ops = { @@ -687,6 +687,12 @@ static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) media_device_init(media_dev); + ret = media_device_register(media_dev); + if (ret) { + dev_err(dev, "failed to register media device: %d\n", ret); + goto error_media; + } + /* V4L2 Control Handler */ ret = v4l2_ctrl_handler_init(&v4l2->ctrl_handler, 0); @@ -746,6 +752,7 @@ static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) v4l2_ctrl_handler_free(&v4l2->ctrl_handler); error_media: + media_device_unregister(media_dev); media_device_cleanup(media_dev); return ret; From patchwork Fri Mar 11 14:34:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778144 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 87C92C433F5 for ; Fri, 11 Mar 2022 14:37:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349708AbiCKOiR (ORCPT ); Fri, 11 Mar 2022 09:38:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58846 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349494AbiCKOhY (ORCPT ); Fri, 11 Mar 2022 09:37:24 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6CC551C8DB4; Fri, 11 Mar 2022 06:36:11 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 7743224000C; Fri, 11 Mar 2022 14:36:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009370; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Wd011+7n71DXlKsfbB1z3rKK7bmQJEGrr2p6llB6W8k=; b=DAjYoDALjWGJL7QzA0cMmjki6qsp7FM6jxM8xOoLJoGgKPEIYzbxqwBuiskn/Nsg/ZBJnz bj4yBH8jknjzA8NChH29aTfiL3tWvwsNne+UWgGpv6VTK1XH5QjR23eXojCqqCEpIqjdCs esHih6Vv4IBrvyHnvj3uCiPZpW3+nKJRJRalryy/MF4mDTnEtnZ3mucaAa8fKhYkgaRfxy tH6ip+oQeVDkmA7fNgbgpeaObPuvR8RsWaaARS/mgdXA2Kdsma2f67brqaDkzOP9WvdgkC wmcIBnBjuZKWCw2J8Wdov9DESiOaT8zNnEArvyzmtqKUqJvcdtj+IVIsX/uuhQ== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 13/46] media: sun6i-csi: Add media ops with link notify callback Date: Fri, 11 Mar 2022 15:34:59 +0100 Message-Id: <20220311143532.265091-14-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org In order to keep the power use count fields balanced when link changes happen between v4l2_pipeline_pm_get/set calls (in open/close), the link_notify media operation callback needs to be registered. Signed-off-by: Paul Kocialkowski --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 38e41e0c8a3c..c340dc5507f6 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "sun6i_csi.h" #include "sun6i_csi_reg.h" @@ -574,6 +575,12 @@ void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable) CSI_CAP_CH0_VCAP_ON); } +/* Media */ + +static const struct media_device_ops sun6i_csi_media_ops = { + .link_notify = v4l2_pipeline_link_notify, +}; + /* V4L2 */ static int sun6i_csi_link_entity(struct sun6i_csi_device *csi_dev, @@ -683,6 +690,7 @@ static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) snprintf(media_dev->bus_info, sizeof(media_dev->bus_info), "platform:%s", dev_name(dev)); media_dev->hw_revision = 0; + media_dev->ops = &sun6i_csi_media_ops; media_dev->dev = dev; media_device_init(media_dev); From patchwork Fri Mar 11 14:35:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778143 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 99D9DC433EF for ; Fri, 11 Mar 2022 14:37:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349691AbiCKOiQ (ORCPT ); Fri, 11 Mar 2022 09:38:16 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58768 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349461AbiCKOhY (ORCPT ); Fri, 11 Mar 2022 09:37:24 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DDC081C8DAF; Fri, 11 Mar 2022 06:36:12 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 1A9C8240012; Fri, 11 Mar 2022 14:36:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009371; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sBf7ZsZre9TfQfmI5vha9jSv0sHiauMmdrFBfvzd4+s=; b=YR6C2NDnd33gjEd8qXogpUA5v3YWiSUW6z/e2LlHs7ZbSsAEWsl8CabJrlIcMgzrpLROjQ jp4eNPxf6/g6gd43xh2IOU7s5/nmgJUVyfHFUBoFnrLatLUQ8jlYdqPxsUuVNXbBXvVTDc 3jG9hkBaZYSp22WGzojEm59GNiG99CGXZMhOTGs3WhP1MdjQLtUU/QefFaE5Ldkx57Nvhh xe8RpoeYzYgVVNrmCji6OxyzTiAy7smKXzOYu/2qx1IuEU/dJwWS9QSFxujl2lOuUG7/NR 7id9bXSTM7Itvild7wrTtfsd9YMY2WnQwreD4M9ZNsg29e3FTcxGFxg91JflUQ== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 14/46] media: sun6i-csi: Introduce and use video helper functions Date: Fri, 11 Mar 2022 15:35:00 +0100 Message-Id: <20220311143532.265091-15-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Introduce some helpers for buffer and general video configuration. Signed-off-by: Paul Kocialkowski --- .../platform/sunxi/sun6i-csi/sun6i_video.c | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index 178dddb0eaf1..6f5470a6859d 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -92,6 +92,29 @@ static bool sun6i_video_format_check(u32 format) return false; } +/* Video */ + +static void sun6i_video_buffer_configure(struct sun6i_csi_device *csi_dev, + struct sun6i_csi_buffer *csi_buffer) +{ + csi_buffer->queued_to_csi = true; + sun6i_csi_update_buf_addr(csi_dev, csi_buffer->dma_addr); +} + +static void sun6i_video_configure(struct sun6i_csi_device *csi_dev) +{ + struct sun6i_video *video = &csi_dev->video; + struct sun6i_csi_config config = { 0 }; + + config.pixelformat = video->format.fmt.pix.pixelformat; + config.code = video->mbus_code; + config.field = video->format.fmt.pix.field; + config.width = video->format.fmt.pix.width; + config.height = video->format.fmt.pix.height; + + sun6i_csi_update_config(csi_dev, &config); +} + /* Queue */ static int sun6i_video_queue_setup(struct vb2_queue *queue, @@ -160,7 +183,6 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue, struct video_device *video_dev = &video->video_dev; struct sun6i_csi_buffer *buf; struct sun6i_csi_buffer *next_buf; - struct sun6i_csi_config config; struct v4l2_subdev *subdev; unsigned long flags; int ret; @@ -182,22 +204,13 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue, goto error_media_pipeline; } - config.pixelformat = video->format.fmt.pix.pixelformat; - config.code = video->mbus_code; - config.field = video->format.fmt.pix.field; - config.width = video->format.fmt.pix.width; - config.height = video->format.fmt.pix.height; - - ret = sun6i_csi_update_config(csi_dev, &config); - if (ret < 0) - goto error_media_pipeline; + sun6i_video_configure(csi_dev); spin_lock_irqsave(&video->dma_queue_lock, flags); buf = list_first_entry(&video->dma_queue, struct sun6i_csi_buffer, list); - buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(csi_dev, buf->dma_addr); + sun6i_video_buffer_configure(csi_dev, buf); sun6i_csi_set_stream(csi_dev, true); @@ -219,8 +232,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue, * would also drop frame when lacking of queued buffer. */ next_buf = list_next_entry(buf, list); - next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(csi_dev, next_buf->dma_addr); + sun6i_video_buffer_configure(csi_dev, next_buf); spin_unlock_irqrestore(&video->dma_queue_lock, flags); @@ -294,8 +306,7 @@ void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev) * for next ISR call. */ if (!next_buf->queued_to_csi) { - next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(csi_dev, next_buf->dma_addr); + sun6i_video_buffer_configure(csi_dev, next_buf); dev_dbg(csi_dev->dev, "Frame dropped!\n"); goto complete; } @@ -309,8 +320,7 @@ void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev) /* Prepare buffer for next frame but one. */ if (!list_is_last(&next_buf->list, &video->dma_queue)) { next_buf = list_next_entry(next_buf, list); - next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(csi_dev, next_buf->dma_addr); + sun6i_video_buffer_configure(csi_dev, next_buf); } else { dev_dbg(csi_dev->dev, "Next frame will be dropped!\n"); } From patchwork Fri Mar 11 14:35:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778142 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A09DEC4332F for ; Fri, 11 Mar 2022 14:37:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349637AbiCKOiQ (ORCPT ); Fri, 11 Mar 2022 09:38:16 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58878 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349502AbiCKOh3 (ORCPT ); Fri, 11 Mar 2022 09:37:29 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 736A11C9467; Fri, 11 Mar 2022 06:36:14 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id A547F240013; Fri, 11 Mar 2022 14:36:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009373; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=s18NrUi/W9m7iDrtX6X6WlrK2Xvr6urYYt5kdcn3Hqo=; b=OLk6XG83H2m8vI7vSd8KrNtGYiUPX7ENKPqxyjx1Vg7dLaIB5rEIWsNCyFjYg0mHL7QNMd aiKO17rSblGaiUCHwBOKRbX7gc/fSGZ2GAzn3G8SyKCJJcxYvp+2K7jXSMoK1lbOEHRsBy u30F6gRusptsrxyxGrbdUhN7pfb3NGcVG677G5S3H8mUFC1vBZjMgijXLAIdP2bLn6OWUs usdJK7NWCJyMGHr20TNofD7TAaEreXu5NwN5XfugGuYim72eqx1ryCUC/c/1ErLqbsWfW/ GvKRnhM9voYErqM5ml3dxePwyzYtmAW1wPhvML5O99Zhb9xO9PLxxiX7/UCuzQ== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni , Maxime Ripard Subject: [PATCH v3 15/46] media: sun6i-csi: Move csi buffer definition to main header file Date: Fri, 11 Mar 2022 15:35:01 +0100 Message-Id: <20220311143532.265091-16-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org The buffer structure is a top-level definition, put it in the main header to keep things tidy. No functional change intended. Signed-off-by: Paul Kocialkowski Reviewed-by: Maxime Ripard --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h | 9 +++++++++ drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c | 8 -------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 3c4a3af6b897..404e304e4ff6 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -11,12 +11,21 @@ #include #include #include +#include #include "sun6i_video.h" #define SUN6I_CSI_NAME "sun6i-csi" #define SUN6I_CSI_DESCRIPTION "Allwinner A31 CSI Device" +struct sun6i_csi_buffer { + struct vb2_v4l2_buffer v4l2_buffer; + struct list_head list; + + dma_addr_t dma_addr; + bool queued_to_csi; +}; + /** * struct sun6i_csi_config - configs for sun6i csi * @pixelformat: v4l2 pixel format (V4L2_PIX_FMT_*) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index 6f5470a6859d..d32ff6b81f8a 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -23,14 +23,6 @@ #define MAX_WIDTH (4800) #define MAX_HEIGHT (4800) -struct sun6i_csi_buffer { - struct vb2_v4l2_buffer v4l2_buffer; - struct list_head list; - - dma_addr_t dma_addr; - bool queued_to_csi; -}; - /* Helpers */ static struct v4l2_subdev * From patchwork Fri Mar 11 14:35:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778140 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 21E8BC433EF for ; Fri, 11 Mar 2022 14:37:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349538AbiCKOiN (ORCPT ); Fri, 11 Mar 2022 09:38:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59388 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349465AbiCKOh3 (ORCPT ); Fri, 11 Mar 2022 09:37:29 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BD1FF1C946C; Fri, 11 Mar 2022 06:36:15 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 3665C240005; Fri, 11 Mar 2022 14:36:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009374; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=WB2XMCKAF+8M94A1ElakRQf0ZmUu65OswSlQP2vcxrg=; b=WYGECr+kvxcKmsFz1fPHatmsvp7X18J/Qrtca2cewhahW1s0Qpt2YJvA7VIfrPAt5+grog Gz2a1j8aK18qIAEkIIJxyTr8w1svLBz2mCAyiVZdO+gQJyV0EXZZFXMKifD4EVA8VWhfO8 9mcmJ/oey8a1c21hJhSHv2wkODiLFGHKOEoJLbvbO5w4U5X/BHQCbSCCwrs8PUdnwYGQy/ fG8KaylFvv8MJWySH2iMXwCTosUoUEuFtDk+e8JUOgs7AIOudiZ8905i81eCaQBYhF5z6t B9tNEOntSIE9Kx8wp8tKhPWlLWwdNRQjTJh0WudpC4IrZnNzjKu2O3E+RwTiQA== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 16/46] media: sun6i-csi: Add bridge v4l2 subdev with port management Date: Fri, 11 Mar 2022 15:35:02 +0100 Message-Id: <20220311143532.265091-17-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Introduce a bridge v4l2 subdev to prepare for separation between the processing part (bridge) and the dma engine, which is required to properly support ths isp workflow later on. Currently the bridge just manages fwnode mapping to media pads, using an async notifier (which was previously in the main code). The s_stream video op just forwards to the connected v4l2 subdev (sensor or MIPI CSI-2 bridge). The video capture device is now registered after the bridge and attaches to it with a media link. Signed-off-by: Paul Kocialkowski --- .../media/platform/sunxi/sun6i-csi/Makefile | 2 +- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 157 +----- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 10 +- .../sunxi/sun6i-csi/sun6i_csi_bridge.c | 472 ++++++++++++++++++ .../sunxi/sun6i-csi/sun6i_csi_bridge.h | 50 ++ .../platform/sunxi/sun6i-csi/sun6i_video.c | 19 + 6 files changed, 571 insertions(+), 139 deletions(-) create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h diff --git a/drivers/media/platform/sunxi/sun6i-csi/Makefile b/drivers/media/platform/sunxi/sun6i-csi/Makefile index e7e315347804..7a699580a641 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/Makefile +++ b/drivers/media/platform/sunxi/sun6i-csi/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -sun6i-csi-y += sun6i_video.o sun6i_csi.o +sun6i-csi-y += sun6i_video.o sun6i_csi.o sun6i_csi_bridge.o obj-$(CONFIG_VIDEO_SUN6I_CSI) += sun6i-csi.o diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index c340dc5507f6..3d9b475634e5 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -34,16 +34,17 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev, u32 pixformat, u32 mbus_code) { - struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; + struct v4l2_fwnode_endpoint *endpoint = + &csi_dev->bridge.source->endpoint; /* * Some video receivers have the ability to be compatible with * 8bit and 16bit bus width. * Identify the media bus format from device tree. */ - if ((v4l2->v4l2_ep.bus_type == V4L2_MBUS_PARALLEL - || v4l2->v4l2_ep.bus_type == V4L2_MBUS_BT656) - && v4l2->v4l2_ep.bus.parallel.bus_width == 16) { + if ((endpoint->bus_type == V4L2_MBUS_PARALLEL + || endpoint->bus_type == V4L2_MBUS_BT656) + && endpoint->bus.parallel.bus_width == 16) { switch (pixformat) { case V4L2_PIX_FMT_NV12_16L16: case V4L2_PIX_FMT_NV12: @@ -328,7 +329,8 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_device *csi_dev, static void sun6i_csi_setup_bus(struct sun6i_csi_device *csi_dev) { - struct v4l2_fwnode_endpoint *endpoint = &csi_dev->v4l2.v4l2_ep; + struct v4l2_fwnode_endpoint *endpoint = + &csi_dev->bridge.source->endpoint; struct sun6i_csi_config *config = &csi_dev->config; unsigned char bus_width; u32 flags; @@ -583,103 +585,11 @@ static const struct media_device_ops sun6i_csi_media_ops = { /* V4L2 */ -static int sun6i_csi_link_entity(struct sun6i_csi_device *csi_dev, - struct media_entity *entity, - struct fwnode_handle *fwnode) -{ - struct media_entity *sink; - struct media_pad *sink_pad; - int src_pad_index; - int ret; - - ret = media_entity_get_fwnode_pad(entity, fwnode, MEDIA_PAD_FL_SOURCE); - if (ret < 0) { - dev_err(csi_dev->dev, - "%s: no source pad in external entity %s\n", __func__, - entity->name); - return -EINVAL; - } - - src_pad_index = ret; - - sink = &csi_dev->video.video_dev.entity; - sink_pad = &csi_dev->video.pad; - - dev_dbg(csi_dev->dev, "creating %s:%u -> %s:%u link\n", - entity->name, src_pad_index, sink->name, sink_pad->index); - ret = media_create_pad_link(entity, src_pad_index, sink, - sink_pad->index, - MEDIA_LNK_FL_ENABLED | - MEDIA_LNK_FL_IMMUTABLE); - if (ret < 0) { - dev_err(csi_dev->dev, "failed to create %s:%u -> %s:%u link\n", - entity->name, src_pad_index, - sink->name, sink_pad->index); - return ret; - } - - return 0; -} - -static int sun6i_subdev_notify_complete(struct v4l2_async_notifier *notifier) -{ - struct sun6i_csi_device *csi_dev = - container_of(notifier, struct sun6i_csi_device, - v4l2.notifier); - struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; - struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev; - struct v4l2_subdev *sd; - int ret; - - dev_dbg(csi_dev->dev, "notify complete, all subdevs registered\n"); - - sd = list_first_entry(&v4l2_dev->subdevs, struct v4l2_subdev, list); - if (!sd) - return -EINVAL; - - ret = sun6i_csi_link_entity(csi_dev, &sd->entity, sd->fwnode); - if (ret < 0) - return ret; - - ret = v4l2_device_register_subdev_nodes(v4l2_dev); - if (ret < 0) - return ret; - - return 0; -} - -static const struct v4l2_async_notifier_operations sun6i_csi_async_ops = { - .complete = sun6i_subdev_notify_complete, -}; - -static int sun6i_csi_fwnode_parse(struct device *dev, - struct v4l2_fwnode_endpoint *vep, - struct v4l2_async_subdev *asd) -{ - struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); - - if (vep->base.port || vep->base.id) { - dev_warn(dev, "Only support a single port with one endpoint\n"); - return -ENOTCONN; - } - - switch (vep->bus_type) { - case V4L2_MBUS_PARALLEL: - case V4L2_MBUS_BT656: - csi_dev->v4l2.v4l2_ep = *vep; - return 0; - default: - dev_err(dev, "Unsupported media bus type\n"); - return -ENOTCONN; - } -} - static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) { struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; struct media_device *media_dev = &v4l2->media_dev; struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev; - struct v4l2_async_notifier *notifier = &v4l2->notifier; struct device *dev = csi_dev->dev; int ret; @@ -720,42 +630,8 @@ static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) goto error_v4l2_ctrl; } - /* Video */ - - ret = sun6i_video_setup(csi_dev); - if (ret) - goto error_v4l2_device; - - /* V4L2 Async */ - - v4l2_async_nf_init(notifier); - notifier->ops = &sun6i_csi_async_ops; - - ret = v4l2_async_nf_parse_fwnode_endpoints(dev, notifier, - sizeof(struct - v4l2_async_subdev), - sun6i_csi_fwnode_parse); - if (ret) - goto error_video; - - ret = v4l2_async_nf_register(v4l2_dev, notifier); - if (ret) { - dev_err(dev, "failed to register v4l2 async notifier: %d\n", - ret); - goto error_v4l2_async_notifier; - } - return 0; -error_v4l2_async_notifier: - v4l2_async_nf_cleanup(notifier); - -error_video: - sun6i_video_cleanup(csi_dev); - -error_v4l2_device: - v4l2_device_unregister(&v4l2->v4l2_dev); - error_v4l2_ctrl: v4l2_ctrl_handler_free(&v4l2->ctrl_handler); @@ -771,9 +647,6 @@ static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev) struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; media_device_unregister(&v4l2->media_dev); - v4l2_async_nf_unregister(&v4l2->notifier); - v4l2_async_nf_cleanup(&v4l2->notifier); - sun6i_video_cleanup(csi_dev); v4l2_device_unregister(&v4l2->v4l2_dev); v4l2_ctrl_handler_free(&v4l2->ctrl_handler); media_device_cleanup(&v4l2->media_dev); @@ -996,8 +869,22 @@ static int sun6i_csi_probe(struct platform_device *platform_dev) if (ret) goto error_resources; + ret = sun6i_csi_bridge_setup(csi_dev); + if (ret) + goto error_v4l2; + + ret = sun6i_video_setup(csi_dev); + if (ret) + goto error_bridge; + return 0; +error_bridge: + sun6i_csi_bridge_cleanup(csi_dev); + +error_v4l2: + sun6i_csi_v4l2_cleanup(csi_dev); + error_resources: sun6i_csi_resources_cleanup(csi_dev); @@ -1008,6 +895,8 @@ static int sun6i_csi_remove(struct platform_device *pdev) { struct sun6i_csi_device *csi_dev = platform_get_drvdata(pdev); + sun6i_video_cleanup(csi_dev); + sun6i_csi_bridge_cleanup(csi_dev); sun6i_csi_v4l2_cleanup(csi_dev); sun6i_csi_resources_cleanup(csi_dev); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 404e304e4ff6..8f0e5cfdda65 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -13,11 +13,16 @@ #include #include +#include "sun6i_csi_bridge.h" #include "sun6i_video.h" #define SUN6I_CSI_NAME "sun6i-csi" #define SUN6I_CSI_DESCRIPTION "Allwinner A31 CSI Device" +enum sun6i_csi_port { + SUN6I_CSI_PORT_PARALLEL = 0, +}; + struct sun6i_csi_buffer { struct vb2_v4l2_buffer v4l2_buffer; struct list_head list; @@ -46,10 +51,6 @@ struct sun6i_csi_v4l2 { struct v4l2_device v4l2_dev; struct v4l2_ctrl_handler ctrl_handler; struct media_device media_dev; - - struct v4l2_async_notifier notifier; - /* video port settings */ - struct v4l2_fwnode_endpoint v4l2_ep; }; struct sun6i_csi_device { @@ -57,6 +58,7 @@ struct sun6i_csi_device { struct sun6i_csi_config config; struct sun6i_csi_v4l2 v4l2; + struct sun6i_csi_bridge bridge; struct sun6i_video video; struct regmap *regmap; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c new file mode 100644 index 000000000000..33309423d1e6 --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c @@ -0,0 +1,472 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021-2022 Bootlin + * Author: Paul Kocialkowski + */ + +#include +#include +#include +#include + +#include "sun6i_csi.h" +#include "sun6i_csi_bridge.h" + +/* Format */ + +static const u32 sun6i_csi_bridge_mbus_codes[] = { + /* Bayer */ + MEDIA_BUS_FMT_SBGGR8_1X8, + MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SGRBG8_1X8, + MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SBGGR12_1X12, + MEDIA_BUS_FMT_SGBRG12_1X12, + MEDIA_BUS_FMT_SGRBG12_1X12, + MEDIA_BUS_FMT_SRGGB12_1X12, + /* RGB */ + MEDIA_BUS_FMT_RGB565_2X8_LE, + MEDIA_BUS_FMT_RGB565_2X8_BE, + /* YUV422 */ + MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_YVYU8_1X16, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_VYUY8_1X16, + /* Compressed */ + MEDIA_BUS_FMT_JPEG_1X8, +}; + +static bool sun6i_csi_bridge_mbus_code_check(u32 mbus_code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sun6i_csi_bridge_mbus_codes); i++) + if (sun6i_csi_bridge_mbus_codes[i] == mbus_code) + return true; + + return false; +} + +/* V4L2 Subdev */ + +static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on) +{ + struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev); + struct v4l2_subdev *source_subdev; + /* Initialize to 0 to use both in disable label (ret != 0) and off. */ + int ret = 0; + + /* Source */ + + if (!csi_dev->bridge.source) + return -ENODEV; + + source_subdev = csi_dev->bridge.source->subdev; + + if (!on) { + v4l2_subdev_call(source_subdev, video, s_stream, 0); + goto disable; + } + + ret = v4l2_subdev_call(source_subdev, video, s_stream, 1); + if (ret && ret != -ENOIOCTLCMD) + goto disable; + + return 0; + +disable: + csi_dev->bridge.source = NULL; + + return ret; +} + +static const struct v4l2_subdev_video_ops sun6i_csi_bridge_video_ops = { + .s_stream = sun6i_csi_bridge_s_stream, +}; + +static void +sun6i_csi_bridge_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format) +{ + if (!sun6i_csi_bridge_mbus_code_check(mbus_format->code)) + mbus_format->code = sun6i_csi_bridge_mbus_codes[0]; + + mbus_format->field = V4L2_FIELD_NONE; + mbus_format->colorspace = V4L2_COLORSPACE_RAW; + mbus_format->quantization = V4L2_QUANTIZATION_DEFAULT; + mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; +} + +static int sun6i_csi_bridge_init_cfg(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state) +{ + struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev); + unsigned int pad = SUN6I_CSI_BRIDGE_PAD_SINK; + struct v4l2_mbus_framefmt *mbus_format = + v4l2_subdev_get_try_format(subdev, state, pad); + struct mutex *lock = &csi_dev->bridge.lock; + + mutex_lock(lock); + + mbus_format->code = sun6i_csi_bridge_mbus_codes[0]; + mbus_format->width = 1280; + mbus_format->height = 720; + + sun6i_csi_bridge_mbus_format_prepare(mbus_format); + + mutex_unlock(lock); + + return 0; +} + +static int +sun6i_csi_bridge_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(sun6i_csi_bridge_mbus_codes)) + return -EINVAL; + + code_enum->code = sun6i_csi_bridge_mbus_codes[code_enum->index]; + + return 0; +} + +static int sun6i_csi_bridge_get_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev); + struct v4l2_mbus_framefmt *mbus_format = &format->format; + struct mutex *lock = &csi_dev->bridge.lock; + + mutex_lock(lock); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + *mbus_format = *v4l2_subdev_get_try_format(subdev, state, + format->pad); + else + *mbus_format = csi_dev->bridge.mbus_format; + + mutex_unlock(lock); + + return 0; +} + +static int sun6i_csi_bridge_set_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev); + struct v4l2_mbus_framefmt *mbus_format = &format->format; + struct mutex *lock = &csi_dev->bridge.lock; + + mutex_lock(lock); + + sun6i_csi_bridge_mbus_format_prepare(mbus_format); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + *v4l2_subdev_get_try_format(subdev, state, format->pad) = + *mbus_format; + else + csi_dev->bridge.mbus_format = *mbus_format; + + mutex_unlock(lock); + + return 0; +} + +static const struct v4l2_subdev_pad_ops sun6i_csi_bridge_pad_ops = { + .init_cfg = sun6i_csi_bridge_init_cfg, + .enum_mbus_code = sun6i_csi_bridge_enum_mbus_code, + .get_fmt = sun6i_csi_bridge_get_fmt, + .set_fmt = sun6i_csi_bridge_set_fmt, +}; + +const struct v4l2_subdev_ops sun6i_csi_bridge_subdev_ops = { + .video = &sun6i_csi_bridge_video_ops, + .pad = &sun6i_csi_bridge_pad_ops, +}; + +/* Media Entity */ + +static int sun6i_csi_bridge_link_validate(struct media_link *link) +{ + struct v4l2_subdev *subdev = + media_entity_to_v4l2_subdev(link->sink->entity); + struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev); + struct sun6i_csi_bridge *bridge = &csi_dev->bridge; + struct device *dev = csi_dev->dev; + struct v4l2_subdev *source_subdev = + media_entity_to_v4l2_subdev(link->source->entity); + int ret; + + /* Only support one enabled source at a time. */ + if (bridge->source) { + dev_err(dev, "multiple sources are connected to the bridge\n"); + return -EBUSY; + } + + ret = v4l2_subdev_link_validate(link); + if (ret) + return ret; + + if (source_subdev == bridge->source_parallel.subdev) + bridge->source = &bridge->source_parallel; + + return 0; +} + +static const struct media_entity_operations sun6i_csi_bridge_entity_ops = { + .link_validate = sun6i_csi_bridge_link_validate, +}; + +/* V4L2 Async */ + +static int sun6i_csi_bridge_link(struct sun6i_csi_device *csi_dev, + int sink_pad_index, + struct v4l2_subdev *remote_subdev, + bool enabled) +{ + struct device *dev = csi_dev->dev; + struct v4l2_subdev *subdev = &csi_dev->bridge.subdev; + struct media_entity *sink_entity = &subdev->entity; + struct media_entity *source_entity = &remote_subdev->entity; + int source_pad_index; + int ret; + + /* Get the first remote source pad. */ + ret = media_entity_get_fwnode_pad(source_entity, remote_subdev->fwnode, + MEDIA_PAD_FL_SOURCE); + if (ret < 0) { + dev_err(dev, "missing source pad in external entity %s\n", + source_entity->name); + return -EINVAL; + } + + source_pad_index = ret; + + dev_dbg(dev, "creating %s:%u -> %s:%u link\n", source_entity->name, + source_pad_index, sink_entity->name, sink_pad_index); + + ret = media_create_pad_link(source_entity, source_pad_index, + sink_entity, sink_pad_index, + enabled ? MEDIA_LNK_FL_ENABLED : 0); + if (ret < 0) { + dev_err(dev, "failed to create %s:%u -> %s:%u link\n", + source_entity->name, source_pad_index, + sink_entity->name, sink_pad_index); + return ret; + } + + return 0; +} + +static int +sun6i_csi_bridge_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *remote_subdev, + struct v4l2_async_subdev *async_subdev) +{ + struct sun6i_csi_device *csi_dev = + container_of(notifier, struct sun6i_csi_device, + bridge.notifier); + struct sun6i_csi_bridge *bridge = &csi_dev->bridge; + struct sun6i_csi_bridge_async_subdev *bridge_async_subdev = + container_of(async_subdev, struct sun6i_csi_bridge_async_subdev, + async_subdev); + struct sun6i_csi_bridge_source *source = bridge_async_subdev->source; + bool enabled; + int ret; + + switch (source->endpoint.base.port) { + case SUN6I_CSI_PORT_PARALLEL: + enabled = true; + break; + default: + break; + } + + source->subdev = remote_subdev; + + return sun6i_csi_bridge_link(csi_dev, SUN6I_CSI_BRIDGE_PAD_SINK, + remote_subdev, enabled); +} + +static int +sun6i_csi_bridge_notifier_complete(struct v4l2_async_notifier *notifier) +{ + struct sun6i_csi_device *csi_dev = + container_of(notifier, struct sun6i_csi_device, + bridge.notifier); + struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; + + return v4l2_device_register_subdev_nodes(v4l2_dev); +} + +static const struct v4l2_async_notifier_operations +sun6i_csi_bridge_notifier_ops = { + .bound = sun6i_csi_bridge_notifier_bound, + .complete = sun6i_csi_bridge_notifier_complete, +}; + +/* Bridge */ + +static int sun6i_csi_bridge_source_setup(struct sun6i_csi_device *csi_dev, + struct sun6i_csi_bridge_source *source, + u32 port, + enum v4l2_mbus_type *bus_types) +{ + struct device *dev = csi_dev->dev; + struct v4l2_async_notifier *notifier = &csi_dev->bridge.notifier; + struct v4l2_fwnode_endpoint *endpoint = &source->endpoint; + struct sun6i_csi_bridge_async_subdev *bridge_async_subdev; + struct fwnode_handle *handle; + int ret; + + handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), port, 0, 0); + if (!handle) + return -ENODEV; + + ret = v4l2_fwnode_endpoint_parse(handle, endpoint); + if (ret) + goto complete; + + if (bus_types) { + bool valid = false; + unsigned int i; + + for (i = 0; bus_types[i] != V4L2_MBUS_INVALID; i++) { + if (endpoint->bus_type == bus_types[i]) { + valid = true; + break; + } + } + + if (!valid) { + dev_err(dev, "unsupported bus type for port %d\n", + port); + ret = -EINVAL; + goto complete; + } + } + + bridge_async_subdev = + v4l2_async_nf_add_fwnode_remote(notifier, handle, + struct + sun6i_csi_bridge_async_subdev); + if (IS_ERR(bridge_async_subdev)) { + ret = PTR_ERR(bridge_async_subdev); + goto complete; + } + + bridge_async_subdev->source = source; + + source->expected = true; + +complete: + fwnode_handle_put(handle); + + return ret; +} + +int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev) +{ + struct device *dev = csi_dev->dev; + struct sun6i_csi_bridge *bridge = &csi_dev->bridge; + struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; + struct v4l2_subdev *subdev = &bridge->subdev; + struct v4l2_async_notifier *notifier = &bridge->notifier; + struct media_pad *pads = bridge->pads; + enum v4l2_mbus_type parallel_mbus_types[] = { + V4L2_MBUS_PARALLEL, + V4L2_MBUS_BT656, + V4L2_MBUS_INVALID + }; + int ret; + + mutex_init(&bridge->lock); + + /* V4L2 Subdev */ + + v4l2_subdev_init(subdev, &sun6i_csi_bridge_subdev_ops); + strscpy(subdev->name, SUN6I_CSI_BRIDGE_NAME, sizeof(subdev->name)); + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + subdev->owner = THIS_MODULE; + subdev->dev = dev; + + v4l2_set_subdevdata(subdev, csi_dev); + + /* Media Entity */ + + subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + subdev->entity.ops = &sun6i_csi_bridge_entity_ops; + + /* Media Pads */ + + pads[SUN6I_CSI_BRIDGE_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + pads[SUN6I_CSI_BRIDGE_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE | + MEDIA_PAD_FL_MUST_CONNECT; + + ret = media_entity_pads_init(&subdev->entity, + SUN6I_CSI_BRIDGE_PAD_COUNT, pads); + if (ret < 0) + return ret; + + /* V4L2 Subdev */ + + ret = v4l2_device_register_subdev(v4l2_dev, subdev); + if (ret) { + dev_err(dev, "failed to register v4l2 subdev: %d\n", ret); + goto error_media_entity; + } + + /* V4L2 Async */ + + v4l2_async_nf_init(notifier); + notifier->ops = &sun6i_csi_bridge_notifier_ops; + + sun6i_csi_bridge_source_setup(csi_dev, &bridge->source_parallel, + SUN6I_CSI_PORT_PARALLEL, + parallel_mbus_types); + + ret = v4l2_async_nf_register(v4l2_dev, notifier); + if (ret) { + dev_err(dev, "failed to register v4l2 async notifier: %d\n", + ret); + goto error_v4l2_async_notifier; + } + + return 0; + +error_v4l2_async_notifier: + v4l2_async_nf_cleanup(notifier); + + v4l2_device_unregister_subdev(subdev); + +error_media_entity: + media_entity_cleanup(&subdev->entity); + + return ret; +} + +void sun6i_csi_bridge_cleanup(struct sun6i_csi_device *csi_dev) +{ + struct v4l2_subdev *subdev = &csi_dev->bridge.subdev; + struct v4l2_async_notifier *notifier = &csi_dev->bridge.notifier; + + v4l2_async_nf_unregister(notifier); + v4l2_async_nf_cleanup(notifier); + + v4l2_device_unregister_subdev(subdev); + + media_entity_cleanup(&subdev->entity); +} diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h new file mode 100644 index 000000000000..55be292d308c --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2021-2022 Bootlin + * Author: Paul Kocialkowski + */ + +#ifndef _SUN6I_CSI_BRIDGE_H_ +#define _SUN6I_CSI_BRIDGE_H_ + +#include +#include + +#define SUN6I_CSI_BRIDGE_NAME "sun6i-csi-bridge" + +enum sun6i_csi_bridge_pad { + SUN6I_CSI_BRIDGE_PAD_SINK = 0, + SUN6I_CSI_BRIDGE_PAD_SOURCE = 1, + SUN6I_CSI_BRIDGE_PAD_COUNT = 2, +}; + +struct sun6i_csi_device; + +struct sun6i_csi_bridge_source { + struct v4l2_subdev *subdev; + struct v4l2_fwnode_endpoint endpoint; + bool expected; +}; + +struct sun6i_csi_bridge_async_subdev { + struct v4l2_async_subdev async_subdev; + struct sun6i_csi_bridge_source *source; +}; + +struct sun6i_csi_bridge { + struct v4l2_subdev subdev; + struct v4l2_async_notifier notifier; + struct media_pad pads[2]; + struct v4l2_mbus_framefmt mbus_format; + struct mutex lock; /* Mbus format lock. */ + + struct sun6i_csi_bridge_source source_parallel; + struct sun6i_csi_bridge_source *source; +}; + +/* Bridge */ + +int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev); +void sun6i_csi_bridge_cleanup(struct sun6i_csi_device *csi_dev); + +#endif diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index d32ff6b81f8a..fa5bf3697ace 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -632,6 +632,7 @@ int sun6i_video_setup(struct sun6i_csi_device *csi_dev) { struct sun6i_video *video = &csi_dev->video; struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; + struct v4l2_subdev *bridge_subdev = &csi_dev->bridge.subdev; struct video_device *video_dev = &video->video_dev; struct vb2_queue *queue = &video->queue; struct media_pad *pad = &video->pad; @@ -715,8 +716,26 @@ int sun6i_video_setup(struct sun6i_csi_device *csi_dev) v4l2_info(v4l2_dev, "device %s registered as %s\n", video_dev->name, video_device_node_name(video_dev)); + /* Media Pad Link */ + + ret = media_create_pad_link(&bridge_subdev->entity, + SUN6I_CSI_BRIDGE_PAD_SOURCE, + &video_dev->entity, 0, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret < 0) { + v4l2_err(v4l2_dev, "failed to create %s:%u -> %s:%u link\n", + bridge_subdev->entity.name, + SUN6I_CSI_BRIDGE_PAD_SOURCE, + video_dev->entity.name, 0); + goto error_video_device; + } + return 0; +error_video_device: + vb2_video_unregister_device(video_dev); + error_media_entity: media_entity_cleanup(&video_dev->entity); From patchwork Fri Mar 11 14:35:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778120 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CB29AC433EF for ; Fri, 11 Mar 2022 14:36:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349524AbiCKOhe (ORCPT ); Fri, 11 Mar 2022 09:37:34 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59418 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349518AbiCKOha (ORCPT ); Fri, 11 Mar 2022 09:37:30 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AAFC81C945F; Fri, 11 Mar 2022 06:36:17 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 7FBD3240014; Fri, 11 Mar 2022 14:36:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009375; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=q7Ris1Kp42w+wah6E0/Tfx1HO3ZRy/DZLPRo6KrCT1M=; b=khSB2X2yOqUZxcLYcU9qZ6dMNU2dEH3BIMpl7ADMCr4E6hMNtvFJS3RetzqnroiSZOnMGi 6W8P5099hxLcA79W6DkwiG2EVnKdbCgVtPphXhmBAyl/RQJqN3IRiNOrBtTwnyYZkg50nL IaPrXHzCFvYMvRGGyitII0kjcf1HBT2YB0uMdMUnYqWfkOrwOnf7r876D6w4p3XvfOPgHn v4Ua6jOnWzL+acdY+fS/+JCOPgCsOgcqiHdopx1tPIZF6mSjzZoWYr+CfbZMV6Gt6mxxxc 90nWrlVtD+XpacWfn6LTDkGgJFy+3LjNipDx0ReSDptyhhMFDVi1G9MMFxbpTA== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni , Maxime Ripard Subject: [PATCH v3 17/46] media: sun6i-csi: Rename sun6i_video to sun6i_csi_capture Date: Fri, 11 Mar 2022 15:35:03 +0100 Message-Id: <20220311143532.265091-18-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org In an effort to distinguish between the core csi engine (to be represented as the bridge) and the dma engine (the capture video device), rename the video component to capture, with the appropriate prefix. No functional change intended. Signed-off-by: Paul Kocialkowski Reviewed-by: Maxime Ripard --- .../media/platform/sunxi/sun6i-csi/Makefile | 2 +- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 6 +- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 4 +- .../{sun6i_video.c => sun6i_csi_capture.c} | 344 +++++++++--------- .../{sun6i_video.h => sun6i_csi_capture.h} | 14 +- 5 files changed, 187 insertions(+), 183 deletions(-) rename drivers/media/platform/sunxi/sun6i-csi/{sun6i_video.c => sun6i_csi_capture.c} (58%) rename drivers/media/platform/sunxi/sun6i-csi/{sun6i_video.h => sun6i_csi_capture.h} (64%) diff --git a/drivers/media/platform/sunxi/sun6i-csi/Makefile b/drivers/media/platform/sunxi/sun6i-csi/Makefile index 7a699580a641..87e7a715140a 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/Makefile +++ b/drivers/media/platform/sunxi/sun6i-csi/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -sun6i-csi-y += sun6i_video.o sun6i_csi.o sun6i_csi_bridge.o +sun6i-csi-y += sun6i_csi.o sun6i_csi_bridge.o sun6i_csi_capture.o obj-$(CONFIG_VIDEO_SUN6I_CSI) += sun6i-csi.o diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 3d9b475634e5..021705fbb7ed 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -677,7 +677,7 @@ static irqreturn_t sun6i_csi_isr(int irq, void *private) } if (status & CSI_CH_INT_STA_FD_PD) - sun6i_video_frame_done(csi_dev); + sun6i_csi_capture_frame_done(csi_dev); regmap_write(regmap, CSI_CH_INT_STA_REG, status); @@ -873,7 +873,7 @@ static int sun6i_csi_probe(struct platform_device *platform_dev) if (ret) goto error_v4l2; - ret = sun6i_video_setup(csi_dev); + ret = sun6i_csi_capture_setup(csi_dev); if (ret) goto error_bridge; @@ -895,7 +895,7 @@ static int sun6i_csi_remove(struct platform_device *pdev) { struct sun6i_csi_device *csi_dev = platform_get_drvdata(pdev); - sun6i_video_cleanup(csi_dev); + sun6i_csi_capture_cleanup(csi_dev); sun6i_csi_bridge_cleanup(csi_dev); sun6i_csi_v4l2_cleanup(csi_dev); sun6i_csi_resources_cleanup(csi_dev); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 8f0e5cfdda65..2f90e50d456d 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -14,7 +14,7 @@ #include #include "sun6i_csi_bridge.h" -#include "sun6i_video.h" +#include "sun6i_csi_capture.h" #define SUN6I_CSI_NAME "sun6i-csi" #define SUN6I_CSI_DESCRIPTION "Allwinner A31 CSI Device" @@ -59,7 +59,7 @@ struct sun6i_csi_device { struct sun6i_csi_config config; struct sun6i_csi_v4l2 v4l2; struct sun6i_csi_bridge bridge; - struct sun6i_video video; + struct sun6i_csi_capture capture; struct regmap *regmap; struct clk *clk_bus; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c similarity index 58% rename from drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c rename to drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index fa5bf3697ace..1ebc2d825838 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -15,7 +15,7 @@ #include #include "sun6i_csi.h" -#include "sun6i_video.h" +#include "sun6i_csi_capture.h" /* This is got from BSP sources. */ #define MIN_WIDTH (32) @@ -26,11 +26,11 @@ /* Helpers */ static struct v4l2_subdev * -sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad) +sun6i_csi_capture_remote_subdev(struct sun6i_csi_capture *capture, u32 *pad) { struct media_pad *remote; - remote = media_entity_remote_pad(&video->pad); + remote = media_entity_remote_pad(&capture->pad); if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) return NULL; @@ -43,7 +43,7 @@ sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad) /* Format */ -static const u32 sun6i_video_formats[] = { +static const u32 sun6i_csi_capture_formats[] = { V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SGBRG8, V4L2_PIX_FMT_SGRBG8, @@ -73,51 +73,52 @@ static const u32 sun6i_video_formats[] = { V4L2_PIX_FMT_JPEG, }; -static bool sun6i_video_format_check(u32 format) +static bool sun6i_csi_capture_format_check(u32 format) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(sun6i_video_formats); i++) - if (sun6i_video_formats[i] == format) + for (i = 0; i < ARRAY_SIZE(sun6i_csi_capture_formats); i++) + if (sun6i_csi_capture_formats[i] == format) return true; return false; } -/* Video */ +/* Capture */ -static void sun6i_video_buffer_configure(struct sun6i_csi_device *csi_dev, - struct sun6i_csi_buffer *csi_buffer) +static void +sun6i_csi_capture_buffer_configure(struct sun6i_csi_device *csi_dev, + struct sun6i_csi_buffer *csi_buffer) { csi_buffer->queued_to_csi = true; sun6i_csi_update_buf_addr(csi_dev, csi_buffer->dma_addr); } -static void sun6i_video_configure(struct sun6i_csi_device *csi_dev) +static void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev) { - struct sun6i_video *video = &csi_dev->video; + struct sun6i_csi_capture *capture = &csi_dev->capture; struct sun6i_csi_config config = { 0 }; - config.pixelformat = video->format.fmt.pix.pixelformat; - config.code = video->mbus_code; - config.field = video->format.fmt.pix.field; - config.width = video->format.fmt.pix.width; - config.height = video->format.fmt.pix.height; + config.pixelformat = capture->format.fmt.pix.pixelformat; + config.code = capture->mbus_code; + config.field = capture->format.fmt.pix.field; + config.width = capture->format.fmt.pix.width; + config.height = capture->format.fmt.pix.height; sun6i_csi_update_config(csi_dev, &config); } /* Queue */ -static int sun6i_video_queue_setup(struct vb2_queue *queue, - unsigned int *buffers_count, - unsigned int *planes_count, - unsigned int sizes[], - struct device *alloc_devs[]) +static int sun6i_csi_capture_queue_setup(struct vb2_queue *queue, + unsigned int *buffers_count, + unsigned int *planes_count, + unsigned int sizes[], + struct device *alloc_devs[]) { struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); - struct sun6i_video *video = &csi_dev->video; - unsigned int size = video->format.fmt.pix.sizeimage; + struct sun6i_csi_capture *capture = &csi_dev->capture; + unsigned int size = capture->format.fmt.pix.sizeimage; if (*planes_count) return sizes[0] < size ? -EINVAL : 0; @@ -128,15 +129,15 @@ static int sun6i_video_queue_setup(struct vb2_queue *queue, return 0; } -static int sun6i_video_buffer_prepare(struct vb2_buffer *buffer) +static int sun6i_csi_capture_buffer_prepare(struct vb2_buffer *buffer) { struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue); - struct sun6i_video *video = &csi_dev->video; + struct sun6i_csi_capture *capture = &csi_dev->capture; struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer); struct sun6i_csi_buffer *csi_buffer = container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer); - unsigned long size = video->format.fmt.pix.sizeimage; + unsigned long size = capture->format.fmt.pix.sizeimage; if (vb2_plane_size(buffer, 0) < size) { v4l2_err(v4l2_dev, "buffer too small (%lu < %lu)\n", @@ -147,62 +148,62 @@ static int sun6i_video_buffer_prepare(struct vb2_buffer *buffer) vb2_set_plane_payload(buffer, 0, size); csi_buffer->dma_addr = vb2_dma_contig_plane_dma_addr(buffer, 0); - v4l2_buffer->field = video->format.fmt.pix.field; + v4l2_buffer->field = capture->format.fmt.pix.field; return 0; } -static void sun6i_video_buffer_queue(struct vb2_buffer *buffer) +static void sun6i_csi_capture_buffer_queue(struct vb2_buffer *buffer) { struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue); - struct sun6i_video *video = &csi_dev->video; + struct sun6i_csi_capture *capture = &csi_dev->capture; struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer); struct sun6i_csi_buffer *csi_buffer = container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer); unsigned long flags; - spin_lock_irqsave(&video->dma_queue_lock, flags); + spin_lock_irqsave(&capture->dma_queue_lock, flags); csi_buffer->queued_to_csi = false; - list_add_tail(&csi_buffer->list, &video->dma_queue); - spin_unlock_irqrestore(&video->dma_queue_lock, flags); + list_add_tail(&csi_buffer->list, &capture->dma_queue); + spin_unlock_irqrestore(&capture->dma_queue_lock, flags); } -static int sun6i_video_start_streaming(struct vb2_queue *queue, - unsigned int count) +static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, + unsigned int count) { struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); - struct sun6i_video *video = &csi_dev->video; - struct video_device *video_dev = &video->video_dev; + struct sun6i_csi_capture *capture = &csi_dev->capture; + struct video_device *video_dev = &capture->video_dev; struct sun6i_csi_buffer *buf; struct sun6i_csi_buffer *next_buf; struct v4l2_subdev *subdev; unsigned long flags; int ret; - video->sequence = 0; + capture->sequence = 0; ret = media_pipeline_start(&video_dev->entity, &video_dev->pipe); if (ret < 0) goto error_dma_queue_flush; - if (video->mbus_code == 0) { + if (capture->mbus_code == 0) { ret = -EINVAL; goto error_media_pipeline; } - subdev = sun6i_video_remote_subdev(video, NULL); + subdev = sun6i_csi_capture_remote_subdev(capture, NULL); if (!subdev) { ret = -EINVAL; goto error_media_pipeline; } - sun6i_video_configure(csi_dev); + sun6i_csi_capture_configure(csi_dev); - spin_lock_irqsave(&video->dma_queue_lock, flags); + spin_lock_irqsave(&capture->dma_queue_lock, flags); - buf = list_first_entry(&video->dma_queue, + buf = list_first_entry(&capture->dma_queue, struct sun6i_csi_buffer, list); - sun6i_video_buffer_configure(csi_dev, buf); + sun6i_csi_capture_buffer_configure(csi_dev, buf); sun6i_csi_set_stream(csi_dev, true); @@ -224,9 +225,9 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue, * would also drop frame when lacking of queued buffer. */ next_buf = list_next_entry(buf, list); - sun6i_video_buffer_configure(csi_dev, next_buf); + sun6i_csi_capture_buffer_configure(csi_dev, next_buf); - spin_unlock_irqrestore(&video->dma_queue_lock, flags); + spin_unlock_irqrestore(&capture->dma_queue_lock, flags); ret = v4l2_subdev_call(subdev, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) @@ -241,52 +242,52 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue, media_pipeline_stop(&video_dev->entity); error_dma_queue_flush: - spin_lock_irqsave(&video->dma_queue_lock, flags); - list_for_each_entry(buf, &video->dma_queue, list) + spin_lock_irqsave(&capture->dma_queue_lock, flags); + list_for_each_entry(buf, &capture->dma_queue, list) vb2_buffer_done(&buf->v4l2_buffer.vb2_buf, VB2_BUF_STATE_QUEUED); - INIT_LIST_HEAD(&video->dma_queue); - spin_unlock_irqrestore(&video->dma_queue_lock, flags); + INIT_LIST_HEAD(&capture->dma_queue); + spin_unlock_irqrestore(&capture->dma_queue_lock, flags); return ret; } -static void sun6i_video_stop_streaming(struct vb2_queue *queue) +static void sun6i_csi_capture_stop_streaming(struct vb2_queue *queue) { struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); - struct sun6i_video *video = &csi_dev->video; + struct sun6i_csi_capture *capture = &csi_dev->capture; struct v4l2_subdev *subdev; unsigned long flags; struct sun6i_csi_buffer *buf; - subdev = sun6i_video_remote_subdev(video, NULL); + subdev = sun6i_csi_capture_remote_subdev(capture, NULL); if (subdev) v4l2_subdev_call(subdev, video, s_stream, 0); sun6i_csi_set_stream(csi_dev, false); - media_pipeline_stop(&video->video_dev.entity); + media_pipeline_stop(&capture->video_dev.entity); /* Release all active buffers */ - spin_lock_irqsave(&video->dma_queue_lock, flags); - list_for_each_entry(buf, &video->dma_queue, list) + spin_lock_irqsave(&capture->dma_queue_lock, flags); + list_for_each_entry(buf, &capture->dma_queue, list) vb2_buffer_done(&buf->v4l2_buffer.vb2_buf, VB2_BUF_STATE_ERROR); - INIT_LIST_HEAD(&video->dma_queue); - spin_unlock_irqrestore(&video->dma_queue_lock, flags); + INIT_LIST_HEAD(&capture->dma_queue); + spin_unlock_irqrestore(&capture->dma_queue_lock, flags); } -void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev) +void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev) { - struct sun6i_video *video = &csi_dev->video; + struct sun6i_csi_capture *capture = &csi_dev->capture; struct sun6i_csi_buffer *buf; struct sun6i_csi_buffer *next_buf; struct vb2_v4l2_buffer *v4l2_buffer; - spin_lock(&video->dma_queue_lock); + spin_lock(&capture->dma_queue_lock); - buf = list_first_entry(&video->dma_queue, + buf = list_first_entry(&capture->dma_queue, struct sun6i_csi_buffer, list); - if (list_is_last(&buf->list, &video->dma_queue)) { + if (list_is_last(&buf->list, &capture->dma_queue)) { dev_dbg(csi_dev->dev, "Frame dropped!\n"); goto complete; } @@ -298,7 +299,7 @@ void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev) * for next ISR call. */ if (!next_buf->queued_to_csi) { - sun6i_video_buffer_configure(csi_dev, next_buf); + sun6i_csi_capture_buffer_configure(csi_dev, next_buf); dev_dbg(csi_dev->dev, "Frame dropped!\n"); goto complete; } @@ -306,39 +307,39 @@ void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev) list_del(&buf->list); v4l2_buffer = &buf->v4l2_buffer; v4l2_buffer->vb2_buf.timestamp = ktime_get_ns(); - v4l2_buffer->sequence = video->sequence; + v4l2_buffer->sequence = capture->sequence; vb2_buffer_done(&v4l2_buffer->vb2_buf, VB2_BUF_STATE_DONE); /* Prepare buffer for next frame but one. */ - if (!list_is_last(&next_buf->list, &video->dma_queue)) { + if (!list_is_last(&next_buf->list, &capture->dma_queue)) { next_buf = list_next_entry(next_buf, list); - sun6i_video_buffer_configure(csi_dev, next_buf); + sun6i_csi_capture_buffer_configure(csi_dev, next_buf); } else { dev_dbg(csi_dev->dev, "Next frame will be dropped!\n"); } complete: - video->sequence++; - spin_unlock(&video->dma_queue_lock); + capture->sequence++; + spin_unlock(&capture->dma_queue_lock); } -static const struct vb2_ops sun6i_video_queue_ops = { - .queue_setup = sun6i_video_queue_setup, - .buf_prepare = sun6i_video_buffer_prepare, - .buf_queue = sun6i_video_buffer_queue, - .start_streaming = sun6i_video_start_streaming, - .stop_streaming = sun6i_video_stop_streaming, +static const struct vb2_ops sun6i_csi_capture_queue_ops = { + .queue_setup = sun6i_csi_capture_queue_setup, + .buf_prepare = sun6i_csi_capture_buffer_prepare, + .buf_queue = sun6i_csi_capture_buffer_queue, + .start_streaming = sun6i_csi_capture_start_streaming, + .stop_streaming = sun6i_csi_capture_stop_streaming, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, }; /* V4L2 Device */ -static int sun6i_video_querycap(struct file *file, void *private, - struct v4l2_capability *capability) +static int sun6i_csi_capture_querycap(struct file *file, void *private, + struct v4l2_capability *capability) { struct sun6i_csi_device *csi_dev = video_drvdata(file); - struct video_device *video_dev = &csi_dev->video.video_dev; + struct video_device *video_dev = &csi_dev->capture.video_dev; strscpy(capability->driver, SUN6I_CSI_NAME, sizeof(capability->driver)); strscpy(capability->card, video_dev->name, sizeof(capability->card)); @@ -348,38 +349,38 @@ static int sun6i_video_querycap(struct file *file, void *private, return 0; } -static int sun6i_video_enum_fmt(struct file *file, void *private, - struct v4l2_fmtdesc *fmtdesc) +static int sun6i_csi_capture_enum_fmt(struct file *file, void *private, + struct v4l2_fmtdesc *fmtdesc) { u32 index = fmtdesc->index; - if (index >= ARRAY_SIZE(sun6i_video_formats)) + if (index >= ARRAY_SIZE(sun6i_csi_capture_formats)) return -EINVAL; - fmtdesc->pixelformat = sun6i_video_formats[index]; + fmtdesc->pixelformat = sun6i_csi_capture_formats[index]; return 0; } -static int sun6i_video_g_fmt(struct file *file, void *private, - struct v4l2_format *format) +static int sun6i_csi_capture_g_fmt(struct file *file, void *private, + struct v4l2_format *format) { struct sun6i_csi_device *csi_dev = video_drvdata(file); - struct sun6i_video *video = &csi_dev->video; + struct sun6i_csi_capture *capture = &csi_dev->capture; - *format = video->format; + *format = capture->format; return 0; } -static int sun6i_video_format_try(struct sun6i_video *video, - struct v4l2_format *format) +static int sun6i_csi_capture_format_try(struct sun6i_csi_capture *capture, + struct v4l2_format *format) { struct v4l2_pix_format *pix_format = &format->fmt.pix; int bpp; - if (!sun6i_video_format_check(pix_format->pixelformat)) - pix_format->pixelformat = sun6i_video_formats[0]; + if (!sun6i_csi_capture_format_check(pix_format->pixelformat)) + pix_format->pixelformat = sun6i_csi_capture_formats[0]; v4l_bound_align_image(&pix_format->width, MIN_WIDTH, MAX_WIDTH, 1, &pix_format->height, MIN_HEIGHT, MAX_WIDTH, 1, 1); @@ -399,43 +400,43 @@ static int sun6i_video_format_try(struct sun6i_video *video, return 0; } -static int sun6i_video_format_set(struct sun6i_video *video, - struct v4l2_format *format) +static int sun6i_csi_capture_format_set(struct sun6i_csi_capture *capture, + struct v4l2_format *format) { int ret; - ret = sun6i_video_format_try(video, format); + ret = sun6i_csi_capture_format_try(capture, format); if (ret) return ret; - video->format = *format; + capture->format = *format; return 0; } -static int sun6i_video_s_fmt(struct file *file, void *private, - struct v4l2_format *format) +static int sun6i_csi_capture_s_fmt(struct file *file, void *private, + struct v4l2_format *format) { struct sun6i_csi_device *csi_dev = video_drvdata(file); - struct sun6i_video *video = &csi_dev->video; + struct sun6i_csi_capture *capture = &csi_dev->capture; - if (vb2_is_busy(&video->queue)) + if (vb2_is_busy(&capture->queue)) return -EBUSY; - return sun6i_video_format_set(video, format); + return sun6i_csi_capture_format_set(capture, format); } -static int sun6i_video_try_fmt(struct file *file, void *private, - struct v4l2_format *format) +static int sun6i_csi_capture_try_fmt(struct file *file, void *private, + struct v4l2_format *format) { struct sun6i_csi_device *csi_dev = video_drvdata(file); - struct sun6i_video *video = &csi_dev->video; + struct sun6i_csi_capture *capture = &csi_dev->capture; - return sun6i_video_format_try(video, format); + return sun6i_csi_capture_format_try(capture, format); } -static int sun6i_video_enum_input(struct file *file, void *private, - struct v4l2_input *input) +static int sun6i_csi_capture_enum_input(struct file *file, void *private, + struct v4l2_input *input) { if (input->index != 0) return -EINVAL; @@ -446,16 +447,16 @@ static int sun6i_video_enum_input(struct file *file, void *private, return 0; } -static int sun6i_video_g_input(struct file *file, void *private, - unsigned int *index) +static int sun6i_csi_capture_g_input(struct file *file, void *private, + unsigned int *index) { *index = 0; return 0; } -static int sun6i_video_s_input(struct file *file, void *private, - unsigned int index) +static int sun6i_csi_capture_s_input(struct file *file, void *private, + unsigned int index) { if (index != 0) return -EINVAL; @@ -463,17 +464,17 @@ static int sun6i_video_s_input(struct file *file, void *private, return 0; } -static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = { - .vidioc_querycap = sun6i_video_querycap, +static const struct v4l2_ioctl_ops sun6i_csi_capture_ioctl_ops = { + .vidioc_querycap = sun6i_csi_capture_querycap, - .vidioc_enum_fmt_vid_cap = sun6i_video_enum_fmt, - .vidioc_g_fmt_vid_cap = sun6i_video_g_fmt, - .vidioc_s_fmt_vid_cap = sun6i_video_s_fmt, - .vidioc_try_fmt_vid_cap = sun6i_video_try_fmt, + .vidioc_enum_fmt_vid_cap = sun6i_csi_capture_enum_fmt, + .vidioc_g_fmt_vid_cap = sun6i_csi_capture_g_fmt, + .vidioc_s_fmt_vid_cap = sun6i_csi_capture_s_fmt, + .vidioc_try_fmt_vid_cap = sun6i_csi_capture_try_fmt, - .vidioc_enum_input = sun6i_video_enum_input, - .vidioc_g_input = sun6i_video_g_input, - .vidioc_s_input = sun6i_video_s_input, + .vidioc_enum_input = sun6i_csi_capture_enum_input, + .vidioc_g_input = sun6i_csi_capture_g_input, + .vidioc_s_input = sun6i_csi_capture_s_input, .vidioc_create_bufs = vb2_ioctl_create_bufs, .vidioc_prepare_buf = vb2_ioctl_prepare_buf, @@ -492,20 +493,20 @@ static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = { /* V4L2 File */ -static int sun6i_video_open(struct file *file) +static int sun6i_csi_capture_open(struct file *file) { struct sun6i_csi_device *csi_dev = video_drvdata(file); - struct sun6i_video *video = &csi_dev->video; + struct sun6i_csi_capture *capture = &csi_dev->capture; int ret = 0; - if (mutex_lock_interruptible(&video->lock)) + if (mutex_lock_interruptible(&capture->lock)) return -ERESTARTSYS; ret = v4l2_fh_open(file); if (ret < 0) goto error_lock; - ret = v4l2_pipeline_pm_get(&video->video_dev.entity); + ret = v4l2_pipeline_pm_get(&capture->video_dev.entity); if (ret < 0) goto error_v4l2_fh; @@ -516,7 +517,7 @@ static int sun6i_video_open(struct file *file) goto error_v4l2_fh; } - mutex_unlock(&video->lock); + mutex_unlock(&capture->lock); return 0; @@ -524,37 +525,37 @@ static int sun6i_video_open(struct file *file) v4l2_fh_release(file); error_lock: - mutex_unlock(&video->lock); + mutex_unlock(&capture->lock); return ret; } -static int sun6i_video_close(struct file *file) +static int sun6i_csi_capture_close(struct file *file) { struct sun6i_csi_device *csi_dev = video_drvdata(file); - struct sun6i_video *video = &csi_dev->video; + struct sun6i_csi_capture *capture = &csi_dev->capture; bool last_close; - mutex_lock(&video->lock); + mutex_lock(&capture->lock); last_close = v4l2_fh_is_singular_file(file); _vb2_fop_release(file, NULL); - v4l2_pipeline_pm_put(&video->video_dev.entity); + v4l2_pipeline_pm_put(&capture->video_dev.entity); /* Power off at last close. */ if (last_close) sun6i_csi_set_power(csi_dev, false); - mutex_unlock(&video->lock); + mutex_unlock(&capture->lock); return 0; } -static const struct v4l2_file_operations sun6i_video_fops = { +static const struct v4l2_file_operations sun6i_csi_capture_fops = { .owner = THIS_MODULE, - .open = sun6i_video_open, - .release = sun6i_video_close, + .open = sun6i_csi_capture_open, + .release = sun6i_csi_capture_close, .unlocked_ioctl = video_ioctl2, .mmap = vb2_fop_mmap, .poll = vb2_fop_poll @@ -562,8 +563,9 @@ static const struct v4l2_file_operations sun6i_video_fops = { /* Media Entity */ -static int sun6i_video_link_validate_get_format(struct media_pad *pad, - struct v4l2_subdev_format *fmt) +static int +sun6i_csi_capture_link_validate_get_format(struct media_pad *pad, + struct v4l2_subdev_format *fmt) { if (is_media_entity_v4l2_subdev(pad->entity)) { struct v4l2_subdev *sd = @@ -577,72 +579,74 @@ static int sun6i_video_link_validate_get_format(struct media_pad *pad, return -EINVAL; } -static int sun6i_video_link_validate(struct media_link *link) +static int sun6i_csi_capture_link_validate(struct media_link *link) { struct video_device *vdev = container_of(link->sink->entity, struct video_device, entity); struct sun6i_csi_device *csi_dev = video_get_drvdata(vdev); - struct sun6i_video *video = &csi_dev->video; + struct sun6i_csi_capture *capture = &csi_dev->capture; struct v4l2_subdev_format source_fmt; int ret; - video->mbus_code = 0; + capture->mbus_code = 0; if (!media_entity_remote_pad(link->sink->entity->pads)) { - dev_info(csi_dev->dev, "video node %s pad not connected\n", + dev_info(csi_dev->dev, "capture node %s pad not connected\n", vdev->name); return -ENOLINK; } - ret = sun6i_video_link_validate_get_format(link->source, &source_fmt); + ret = sun6i_csi_capture_link_validate_get_format(link->source, + &source_fmt); if (ret < 0) return ret; if (!sun6i_csi_is_format_supported(csi_dev, - video->format.fmt.pix.pixelformat, + capture->format.fmt.pix.pixelformat, source_fmt.format.code)) { dev_err(csi_dev->dev, "Unsupported pixformat: 0x%x with mbus code: 0x%x!\n", - video->format.fmt.pix.pixelformat, + capture->format.fmt.pix.pixelformat, source_fmt.format.code); return -EPIPE; } - if (source_fmt.format.width != video->format.fmt.pix.width || - source_fmt.format.height != video->format.fmt.pix.height) { + if (source_fmt.format.width != capture->format.fmt.pix.width || + source_fmt.format.height != capture->format.fmt.pix.height) { dev_err(csi_dev->dev, "Wrong width or height %ux%u (%ux%u expected)\n", - video->format.fmt.pix.width, video->format.fmt.pix.height, + capture->format.fmt.pix.width, + capture->format.fmt.pix.height, source_fmt.format.width, source_fmt.format.height); return -EPIPE; } - video->mbus_code = source_fmt.format.code; + capture->mbus_code = source_fmt.format.code; return 0; } -static const struct media_entity_operations sun6i_video_media_ops = { - .link_validate = sun6i_video_link_validate +static const struct media_entity_operations sun6i_csi_capture_media_ops = { + .link_validate = sun6i_csi_capture_link_validate }; -/* Video */ +/* Capture */ -int sun6i_video_setup(struct sun6i_csi_device *csi_dev) +int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev) { - struct sun6i_video *video = &csi_dev->video; + struct sun6i_csi_capture *capture = &csi_dev->capture; struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; struct v4l2_subdev *bridge_subdev = &csi_dev->bridge.subdev; - struct video_device *video_dev = &video->video_dev; - struct vb2_queue *queue = &video->queue; - struct media_pad *pad = &video->pad; + struct video_device *video_dev = &capture->video_dev; + struct vb2_queue *queue = &capture->queue; + struct media_pad *pad = &capture->pad; struct v4l2_format format = { 0 }; struct v4l2_pix_format *pix_format = &format.fmt.pix; int ret; /* Media Entity */ - video_dev->entity.ops = &sun6i_video_media_ops; + video_dev->entity.ops = &sun6i_csi_capture_media_ops; /* Media Pad */ @@ -654,22 +658,22 @@ int sun6i_video_setup(struct sun6i_csi_device *csi_dev) /* DMA queue */ - INIT_LIST_HEAD(&video->dma_queue); - spin_lock_init(&video->dma_queue_lock); + INIT_LIST_HEAD(&capture->dma_queue); + spin_lock_init(&capture->dma_queue_lock); - video->sequence = 0; + capture->sequence = 0; /* Queue */ - mutex_init(&video->lock); + mutex_init(&capture->lock); queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; queue->io_modes = VB2_MMAP | VB2_DMABUF; queue->buf_struct_size = sizeof(struct sun6i_csi_buffer); - queue->ops = &sun6i_video_queue_ops; + queue->ops = &sun6i_csi_capture_queue_ops; queue->mem_ops = &vb2_dma_contig_memops; queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - queue->lock = &video->lock; + queue->lock = &capture->lock; queue->dev = csi_dev->dev; queue->drv_priv = csi_dev; @@ -685,12 +689,12 @@ int sun6i_video_setup(struct sun6i_csi_device *csi_dev) /* V4L2 Format */ format.type = queue->type; - pix_format->pixelformat = sun6i_video_formats[0]; + pix_format->pixelformat = sun6i_csi_capture_formats[0]; pix_format->width = 1280; pix_format->height = 720; pix_format->field = V4L2_FIELD_NONE; - sun6i_video_format_set(video, &format); + sun6i_csi_capture_format_set(capture, &format); /* Video Device */ @@ -698,11 +702,11 @@ int sun6i_video_setup(struct sun6i_csi_device *csi_dev) video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; video_dev->vfl_dir = VFL_DIR_RX; video_dev->release = video_device_release_empty; - video_dev->fops = &sun6i_video_fops; - video_dev->ioctl_ops = &sun6i_video_ioctl_ops; + video_dev->fops = &sun6i_csi_capture_fops; + video_dev->ioctl_ops = &sun6i_csi_capture_ioctl_ops; video_dev->v4l2_dev = v4l2_dev; video_dev->queue = queue; - video_dev->lock = &video->lock; + video_dev->lock = &capture->lock; video_set_drvdata(video_dev, csi_dev); @@ -739,17 +743,17 @@ int sun6i_video_setup(struct sun6i_csi_device *csi_dev) error_media_entity: media_entity_cleanup(&video_dev->entity); - mutex_destroy(&video->lock); + mutex_destroy(&capture->lock); return ret; } -void sun6i_video_cleanup(struct sun6i_csi_device *csi_dev) +void sun6i_csi_capture_cleanup(struct sun6i_csi_device *csi_dev) { - struct sun6i_video *video = &csi_dev->video; - struct video_device *video_dev = &video->video_dev; + struct sun6i_csi_capture *capture = &csi_dev->capture; + struct video_device *video_dev = &capture->video_dev; vb2_video_unregister_device(video_dev); media_entity_cleanup(&video_dev->entity); - mutex_destroy(&video->lock); + mutex_destroy(&capture->lock); } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h similarity index 64% rename from drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h rename to drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h index a917d2da6deb..36bba31fcb48 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h @@ -5,15 +5,15 @@ * Author: Yong Deng */ -#ifndef __SUN6I_VIDEO_H__ -#define __SUN6I_VIDEO_H__ +#ifndef __SUN6I_CAPTURE_H__ +#define __SUN6I_CAPTURE_H__ #include #include struct sun6i_csi_device; -struct sun6i_video { +struct sun6i_csi_capture { struct video_device video_dev; struct vb2_queue queue; struct mutex lock; /* Queue lock. */ @@ -27,9 +27,9 @@ struct sun6i_video { unsigned int sequence; }; -int sun6i_video_setup(struct sun6i_csi_device *csi_dev); -void sun6i_video_cleanup(struct sun6i_csi_device *csi_dev); +int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev); +void sun6i_csi_capture_cleanup(struct sun6i_csi_device *csi_dev); -void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev); +void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev); -#endif /* __SUN6I_VIDEO_H__ */ +#endif /* __SUN6I_CAPTURE_H__ */ From patchwork Fri Mar 11 14:35:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778121 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A633AC433F5 for ; Fri, 11 Mar 2022 14:36:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349532AbiCKOhg (ORCPT ); Fri, 11 Mar 2022 09:37:36 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59146 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349523AbiCKOha (ORCPT ); Fri, 11 Mar 2022 09:37:30 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C87051C9B41; Fri, 11 Mar 2022 06:36:18 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 06649240002; Fri, 11 Mar 2022 14:36:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009377; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/XaOP5cfuMYE4MOsQkkGrTw9LUal67MMVnPcFv9G0F4=; b=i0Uezjawxy8LT70SFwFlR1FxHoeMcTAYjbrTDTvfTC1idry87ET4HHjpIR9mWkoo8KNUp5 eDs+ZK9C7+XE6YRSUYOYRWKvyrY1chhSj3S63bITBFJLL//kjH5HuU+yEbuuvHGKX8V1vq 0QUYCFZrQDOEK3gLXw3sUN+ix7HXLSty1eyqOKGj5HsWj1K4Z09bXd743p1b2lnhLCDwrL 1ynNK2mMdM3pGc+IvRkOOdfye+gX0L5fKllnce9X42YQegIuF7MdV1wH3T+GdNDmqv7I0O gxPK9Bio6MWOTsPQxjC/k0CnEqlQKzf3pJYDqnvPl1JprGrXm2h2RKFRap5OTw== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 18/46] media: sun6i-csi: Add capture state using vsync for page flip Date: Fri, 11 Mar 2022 15:35:04 +0100 Message-Id: <20220311143532.265091-19-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org The current implementation requires up to 3 buffers to properly implement page flipping without losing frames: one is configured before the video stream is started, one just after that and page flipping is synchronized to the frame done interrupt. The comment in the code mentions that "CSI will lookup the next dma buffer for next frame before the current frame done IRQ triggered". Based on observations of the CSI unit behavior, it seems that the buffer DMA address is sampled when the frame scan begins (in addition to starting the stream), which corresponds to the vblank interrupt that hits just before the frame-done interrupt of the previous frame. As a result, the address configured at the frame done interrupt is not actually used for the next frame but for the one after that. This proposal changes the page flipping sync point to the vsync interrupt, which allows the DMA address to be sampled for the next frame instead and allows operating with only two buffers. In addition to the change in the sync point, the code is refactored to introduce a notion of state that clarifies tracking of the buffers with tidy functions. Signed-off-by: Paul Kocialkowski --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 4 + .../platform/sunxi/sun6i-csi/sun6i_csi.h | 3 - .../sunxi/sun6i-csi/sun6i_csi_capture.c | 259 ++++++++++-------- .../sunxi/sun6i-csi/sun6i_csi_capture.h | 23 +- 4 files changed, 165 insertions(+), 124 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 021705fbb7ed..69a510014d42 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -566,6 +566,7 @@ void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable) regmap_write(regmap, CSI_CH_INT_STA_REG, 0xFF); regmap_write(regmap, CSI_CH_INT_EN_REG, + CSI_CH_INT_EN_VS_INT_EN | CSI_CH_INT_EN_HB_OF_INT_EN | CSI_CH_INT_EN_FIFO2_OF_INT_EN | CSI_CH_INT_EN_FIFO1_OF_INT_EN | @@ -679,6 +680,9 @@ static irqreturn_t sun6i_csi_isr(int irq, void *private) if (status & CSI_CH_INT_STA_FD_PD) sun6i_csi_capture_frame_done(csi_dev); + if (status & CSI_CH_INT_STA_VS_PD) + sun6i_csi_capture_sync(csi_dev); + regmap_write(regmap, CSI_CH_INT_STA_REG, status); return IRQ_HANDLED; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 2f90e50d456d..b7e51447accb 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -26,9 +26,6 @@ enum sun6i_csi_port { struct sun6i_csi_buffer { struct vb2_v4l2_buffer v4l2_buffer; struct list_head list; - - dma_addr_t dma_addr; - bool queued_to_csi; }; /** diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 1ebc2d825838..bcbb4ffbb517 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -90,8 +90,13 @@ static void sun6i_csi_capture_buffer_configure(struct sun6i_csi_device *csi_dev, struct sun6i_csi_buffer *csi_buffer) { - csi_buffer->queued_to_csi = true; - sun6i_csi_update_buf_addr(csi_dev, csi_buffer->dma_addr); + struct vb2_buffer *vb2_buffer; + dma_addr_t address; + + vb2_buffer = &csi_buffer->v4l2_buffer.vb2_buf; + address = vb2_dma_contig_plane_dma_addr(vb2_buffer, 0); + + sun6i_csi_update_buf_addr(csi_dev, address); } static void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev) @@ -108,6 +113,119 @@ static void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev) sun6i_csi_update_config(csi_dev, &config); } +/* State */ + +static void sun6i_csi_capture_state_cleanup(struct sun6i_csi_device *csi_dev, + bool error) +{ + struct sun6i_csi_capture_state *state = &csi_dev->capture.state; + struct sun6i_csi_buffer **csi_buffer_states[] = { + &state->pending, &state->current, &state->complete, + }; + struct sun6i_csi_buffer *csi_buffer; + struct vb2_buffer *vb2_buffer; + unsigned long flags; + unsigned int i; + + spin_lock_irqsave(&state->lock, flags); + + for (i = 0; i < ARRAY_SIZE(csi_buffer_states); i++) { + csi_buffer = *csi_buffer_states[i]; + if (!csi_buffer) + continue; + + vb2_buffer = &csi_buffer->v4l2_buffer.vb2_buf; + vb2_buffer_done(vb2_buffer, error ? VB2_BUF_STATE_ERROR : + VB2_BUF_STATE_QUEUED); + + *csi_buffer_states[i] = NULL; + } + + list_for_each_entry(csi_buffer, &state->queue, list) { + vb2_buffer = &csi_buffer->v4l2_buffer.vb2_buf; + vb2_buffer_done(vb2_buffer, error ? VB2_BUF_STATE_ERROR : + VB2_BUF_STATE_QUEUED); + } + + INIT_LIST_HEAD(&state->queue); + + spin_unlock_irqrestore(&state->lock, flags); +} + +static void sun6i_csi_capture_state_update(struct sun6i_csi_device *csi_dev) +{ + struct sun6i_csi_capture_state *state = &csi_dev->capture.state; + struct sun6i_csi_buffer *csi_buffer; + unsigned long flags; + + spin_lock_irqsave(&state->lock, flags); + + if (list_empty(&state->queue)) + goto complete; + + if (state->pending) + goto complete; + + csi_buffer = list_first_entry(&state->queue, struct sun6i_csi_buffer, + list); + + sun6i_csi_capture_buffer_configure(csi_dev, csi_buffer); + + list_del(&csi_buffer->list); + + state->pending = csi_buffer; + +complete: + spin_unlock_irqrestore(&state->lock, flags); +} + +static void sun6i_csi_capture_state_complete(struct sun6i_csi_device *csi_dev) +{ + struct sun6i_csi_capture_state *state = &csi_dev->capture.state; + unsigned long flags; + + spin_lock_irqsave(&state->lock, flags); + + if (!state->pending) + goto complete; + + state->complete = state->current; + state->current = state->pending; + state->pending = NULL; + + if (state->complete) { + struct sun6i_csi_buffer *csi_buffer = state->complete; + struct vb2_buffer *vb2_buffer = + &csi_buffer->v4l2_buffer.vb2_buf; + + vb2_buffer->timestamp = ktime_get_ns(); + csi_buffer->v4l2_buffer.sequence = state->sequence; + + vb2_buffer_done(vb2_buffer, VB2_BUF_STATE_DONE); + + state->complete = NULL; + } + +complete: + spin_unlock_irqrestore(&state->lock, flags); +} + +void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev) +{ + struct sun6i_csi_capture_state *state = &csi_dev->capture.state; + unsigned long flags; + + spin_lock_irqsave(&state->lock, flags); + state->sequence++; + spin_unlock_irqrestore(&state->lock, flags); +} + +void sun6i_csi_capture_sync(struct sun6i_csi_device *csi_dev) +{ + sun6i_csi_capture_state_complete(csi_dev); + sun6i_csi_capture_state_update(csi_dev); +} + /* Queue */ static int sun6i_csi_capture_queue_setup(struct vb2_queue *queue, @@ -117,8 +235,7 @@ static int sun6i_csi_capture_queue_setup(struct vb2_queue *queue, struct device *alloc_devs[]) { struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); - struct sun6i_csi_capture *capture = &csi_dev->capture; - unsigned int size = capture->format.fmt.pix.sizeimage; + unsigned int size = csi_dev->capture.format.fmt.pix.sizeimage; if (*planes_count) return sizes[0] < size ? -EINVAL : 0; @@ -135,8 +252,6 @@ static int sun6i_csi_capture_buffer_prepare(struct vb2_buffer *buffer) struct sun6i_csi_capture *capture = &csi_dev->capture; struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer); - struct sun6i_csi_buffer *csi_buffer = - container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer); unsigned long size = capture->format.fmt.pix.sizeimage; if (vb2_plane_size(buffer, 0) < size) { @@ -147,7 +262,6 @@ static int sun6i_csi_capture_buffer_prepare(struct vb2_buffer *buffer) vb2_set_plane_payload(buffer, 0, size); - csi_buffer->dma_addr = vb2_dma_contig_plane_dma_addr(buffer, 0); v4l2_buffer->field = capture->format.fmt.pix.field; return 0; @@ -156,16 +270,15 @@ static int sun6i_csi_capture_buffer_prepare(struct vb2_buffer *buffer) static void sun6i_csi_capture_buffer_queue(struct vb2_buffer *buffer) { struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue); - struct sun6i_csi_capture *capture = &csi_dev->capture; + struct sun6i_csi_capture_state *state = &csi_dev->capture.state; struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer); struct sun6i_csi_buffer *csi_buffer = container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer); unsigned long flags; - spin_lock_irqsave(&capture->dma_queue_lock, flags); - csi_buffer->queued_to_csi = false; - list_add_tail(&csi_buffer->list, &capture->dma_queue); - spin_unlock_irqrestore(&capture->dma_queue_lock, flags); + spin_lock_irqsave(&state->lock, flags); + list_add_tail(&csi_buffer->list, &state->queue); + spin_unlock_irqrestore(&state->lock, flags); } static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, @@ -173,18 +286,16 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, { struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); struct sun6i_csi_capture *capture = &csi_dev->capture; + struct sun6i_csi_capture_state *state = &capture->state; struct video_device *video_dev = &capture->video_dev; - struct sun6i_csi_buffer *buf; - struct sun6i_csi_buffer *next_buf; struct v4l2_subdev *subdev; - unsigned long flags; int ret; - capture->sequence = 0; + state->sequence = 0; ret = media_pipeline_start(&video_dev->entity, &video_dev->pipe); if (ret < 0) - goto error_dma_queue_flush; + goto error_state; if (capture->mbus_code == 0) { ret = -EINVAL; @@ -197,37 +308,17 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, goto error_media_pipeline; } + /* Configure */ + sun6i_csi_capture_configure(csi_dev); - spin_lock_irqsave(&capture->dma_queue_lock, flags); + /* State Update */ - buf = list_first_entry(&capture->dma_queue, - struct sun6i_csi_buffer, list); - sun6i_csi_capture_buffer_configure(csi_dev, buf); + sun6i_csi_capture_state_update(csi_dev); - sun6i_csi_set_stream(csi_dev, true); + /* Enable */ - /* - * CSI will lookup the next dma buffer for next frame before the - * the current frame done IRQ triggered. This is not documented - * but reported by Ondřej Jirman. - * The BSP code has workaround for this too. It skip to mark the - * first buffer as frame done for VB2 and pass the second buffer - * to CSI in the first frame done ISR call. Then in second frame - * done ISR call, it mark the first buffer as frame done for VB2 - * and pass the third buffer to CSI. And so on. The bad thing is - * that the first buffer will be written twice and the first frame - * is dropped even the queued buffer is sufficient. - * So, I make some improvement here. Pass the next buffer to CSI - * just follow starting the CSI. In this case, the first frame - * will be stored in first buffer, second frame in second buffer. - * This method is used to avoid dropping the first frame, it - * would also drop frame when lacking of queued buffer. - */ - next_buf = list_next_entry(buf, list); - sun6i_csi_capture_buffer_configure(csi_dev, next_buf); - - spin_unlock_irqrestore(&capture->dma_queue_lock, flags); + sun6i_csi_set_stream(csi_dev, true); ret = v4l2_subdev_call(subdev, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) @@ -241,13 +332,8 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, error_media_pipeline: media_pipeline_stop(&video_dev->entity); -error_dma_queue_flush: - spin_lock_irqsave(&capture->dma_queue_lock, flags); - list_for_each_entry(buf, &capture->dma_queue, list) - vb2_buffer_done(&buf->v4l2_buffer.vb2_buf, - VB2_BUF_STATE_QUEUED); - INIT_LIST_HEAD(&capture->dma_queue); - spin_unlock_irqrestore(&capture->dma_queue_lock, flags); +error_state: + sun6i_csi_capture_state_cleanup(csi_dev, false); return ret; } @@ -257,8 +343,6 @@ static void sun6i_csi_capture_stop_streaming(struct vb2_queue *queue) struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); struct sun6i_csi_capture *capture = &csi_dev->capture; struct v4l2_subdev *subdev; - unsigned long flags; - struct sun6i_csi_buffer *buf; subdev = sun6i_csi_capture_remote_subdev(capture, NULL); if (subdev) @@ -268,59 +352,7 @@ static void sun6i_csi_capture_stop_streaming(struct vb2_queue *queue) media_pipeline_stop(&capture->video_dev.entity); - /* Release all active buffers */ - spin_lock_irqsave(&capture->dma_queue_lock, flags); - list_for_each_entry(buf, &capture->dma_queue, list) - vb2_buffer_done(&buf->v4l2_buffer.vb2_buf, VB2_BUF_STATE_ERROR); - INIT_LIST_HEAD(&capture->dma_queue); - spin_unlock_irqrestore(&capture->dma_queue_lock, flags); -} - -void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev) -{ - struct sun6i_csi_capture *capture = &csi_dev->capture; - struct sun6i_csi_buffer *buf; - struct sun6i_csi_buffer *next_buf; - struct vb2_v4l2_buffer *v4l2_buffer; - - spin_lock(&capture->dma_queue_lock); - - buf = list_first_entry(&capture->dma_queue, - struct sun6i_csi_buffer, list); - if (list_is_last(&buf->list, &capture->dma_queue)) { - dev_dbg(csi_dev->dev, "Frame dropped!\n"); - goto complete; - } - - next_buf = list_next_entry(buf, list); - /* If a new buffer (#next_buf) had not been queued to CSI, the old - * buffer (#buf) is still holding by CSI for storing the next - * frame. So, we queue a new buffer (#next_buf) to CSI then wait - * for next ISR call. - */ - if (!next_buf->queued_to_csi) { - sun6i_csi_capture_buffer_configure(csi_dev, next_buf); - dev_dbg(csi_dev->dev, "Frame dropped!\n"); - goto complete; - } - - list_del(&buf->list); - v4l2_buffer = &buf->v4l2_buffer; - v4l2_buffer->vb2_buf.timestamp = ktime_get_ns(); - v4l2_buffer->sequence = capture->sequence; - vb2_buffer_done(&v4l2_buffer->vb2_buf, VB2_BUF_STATE_DONE); - - /* Prepare buffer for next frame but one. */ - if (!list_is_last(&next_buf->list, &capture->dma_queue)) { - next_buf = list_next_entry(next_buf, list); - sun6i_csi_capture_buffer_configure(csi_dev, next_buf); - } else { - dev_dbg(csi_dev->dev, "Next frame will be dropped!\n"); - } - -complete: - capture->sequence++; - spin_unlock(&capture->dma_queue_lock); + sun6i_csi_capture_state_cleanup(csi_dev, true); } static const struct vb2_ops sun6i_csi_capture_queue_ops = { @@ -635,6 +667,7 @@ static const struct media_entity_operations sun6i_csi_capture_media_ops = { int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev) { struct sun6i_csi_capture *capture = &csi_dev->capture; + struct sun6i_csi_capture_state *state = &capture->state; struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; struct v4l2_subdev *bridge_subdev = &csi_dev->bridge.subdev; struct video_device *video_dev = &capture->video_dev; @@ -644,6 +677,11 @@ int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev) struct v4l2_pix_format *pix_format = &format.fmt.pix; int ret; + /* State */ + + INIT_LIST_HEAD(&state->queue); + spin_lock_init(&state->lock); + /* Media Entity */ video_dev->entity.ops = &sun6i_csi_capture_media_ops; @@ -656,13 +694,6 @@ int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev) if (ret < 0) return ret; - /* DMA queue */ - - INIT_LIST_HEAD(&capture->dma_queue); - spin_lock_init(&capture->dma_queue_lock); - - capture->sequence = 0; - /* Queue */ mutex_init(&capture->lock); @@ -672,14 +703,12 @@ int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev) queue->buf_struct_size = sizeof(struct sun6i_csi_buffer); queue->ops = &sun6i_csi_capture_queue_ops; queue->mem_ops = &vb2_dma_contig_memops; + queue->min_buffers_needed = 2; queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; queue->lock = &capture->lock; queue->dev = csi_dev->dev; queue->drv_priv = csi_dev; - /* Make sure non-dropped frame. */ - queue->min_buffers_needed = 3; - ret = vb2_queue_init(queue); if (ret) { v4l2_err(v4l2_dev, "failed to initialize vb2 queue: %d\n", ret); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h index 36bba31fcb48..7fa66a2af5ec 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h @@ -13,23 +13,34 @@ struct sun6i_csi_device; +#undef current +struct sun6i_csi_capture_state { + struct list_head queue; + spinlock_t lock; /* Queue and buffers lock. */ + + struct sun6i_csi_buffer *pending; + struct sun6i_csi_buffer *current; + struct sun6i_csi_buffer *complete; + + unsigned int sequence; +}; + struct sun6i_csi_capture { + struct sun6i_csi_capture_state state; + struct video_device video_dev; struct vb2_queue queue; struct mutex lock; /* Queue lock. */ struct media_pad pad; - struct list_head dma_queue; - spinlock_t dma_queue_lock; /* DMA queue lock. */ - struct v4l2_format format; u32 mbus_code; - unsigned int sequence; }; +void sun6i_csi_capture_sync(struct sun6i_csi_device *csi_dev); +void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev); + int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev); void sun6i_csi_capture_cleanup(struct sun6i_csi_device *csi_dev); -void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev); - #endif /* __SUN6I_CAPTURE_H__ */ From patchwork Fri Mar 11 14:35:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778127 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 03503C4332F for ; Fri, 11 Mar 2022 14:36:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343533AbiCKOhy (ORCPT ); Fri, 11 Mar 2022 09:37:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59148 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349534AbiCKOhb (ORCPT ); Fri, 11 Mar 2022 09:37:31 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 796011C9B56; Fri, 11 Mar 2022 06:36:20 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 863F1240015; Fri, 11 Mar 2022 14:36:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009378; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=VXeq2Qwp6Aly274NM3BZEzGGL53Lttah/NY691lrUtw=; b=Id4QgCnfKePtICiIeFmeFGT3ZK2WpFpuenprj7uVm0DehrtUhuBoDCcXo9GXSlWF/h0/by jl4roXxMD07wEkcTJ0+xSjy5LX8ez/jgFRME8TCAHCPnjnCCMcyes0FTd+gSjQTxkidnGc 1J+VqX1Yxi/jZt1dWfMHFHbZE+WxOtxMYxhbG0tNZm7Ur/pwt/vfaAlk9nLZiwzF4ZVd+6 rNWWTBF6r1FTRA6lDkn7RP6382COXkbOnOhzmCilFmg75ubp4+p7NjTIZQcf7xMNk95JOr L1MXwVBGDDzlQQNl+PWEBiL4Q0FfP/3LGVowGEaLaYHSqtSYkoDaZSxHo4IHPw== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 19/46] media: sun6i-csi: Rework register definitions, invert misleading fields Date: Fri, 11 Mar 2022 15:35:05 +0100 Message-Id: <20220311143532.265091-20-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org This cleans up the register definitions a bit, adds a prefix, remove masks. Registers are now fully defined, some additional fields were added when needed. New format definitions are added for future use. Some fields are wrongly defined (inverted) in Allwinner litterature (e.g. field vs frame prefixes), which is quite misleading. They are now corrected to reflect their actual behavior. This should only be a cosmetic commit. No functional change intended. Signed-off-by: Paul Kocialkowski --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 182 ++++++----- .../platform/sunxi/sun6i-csi/sun6i_csi_reg.h | 296 ++++++++++-------- 2 files changed, 266 insertions(+), 212 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 69a510014d42..d0f08173d6ad 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -155,7 +155,8 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) int ret; if (!enable) { - regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0); + regmap_update_bits(regmap, SUN6I_CSI_EN_REG, + SUN6I_CSI_EN_CSI_EN, 0); pm_runtime_put(dev); return 0; @@ -165,7 +166,8 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) if (ret < 0) return ret; - regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, CSI_EN_CSI_EN); + regmap_update_bits(regmap, SUN6I_CSI_EN_REG, SUN6I_CSI_EN_CSI_EN, + SUN6I_CSI_EN_CSI_EN); return 0; } @@ -334,7 +336,7 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_device *csi_dev) struct sun6i_csi_config *config = &csi_dev->config; unsigned char bus_width; u32 flags; - u32 cfg; + u32 cfg = 0; bool input_interlaced = false; if (config->field == V4L2_FIELD_INTERLACED @@ -344,52 +346,63 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_device *csi_dev) bus_width = endpoint->bus.parallel.bus_width; - regmap_read(csi_dev->regmap, CSI_IF_CFG_REG, &cfg); - - cfg &= ~(CSI_IF_CFG_CSI_IF_MASK | CSI_IF_CFG_MIPI_IF_MASK | - CSI_IF_CFG_IF_DATA_WIDTH_MASK | - CSI_IF_CFG_CLK_POL_MASK | CSI_IF_CFG_VREF_POL_MASK | - CSI_IF_CFG_HREF_POL_MASK | CSI_IF_CFG_FIELD_MASK | - CSI_IF_CFG_SRC_TYPE_MASK); - if (input_interlaced) - cfg |= CSI_IF_CFG_SRC_TYPE_INTERLACED; + cfg |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED | + SUN6I_CSI_IF_CFG_FIELD_DT_PCLK_SHIFT(1) | + SUN6I_CSI_IF_CFG_FIELD_DT_FIELD_VSYNC; else - cfg |= CSI_IF_CFG_SRC_TYPE_PROGRESSED; + cfg |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE; switch (endpoint->bus_type) { case V4L2_MBUS_PARALLEL: - cfg |= CSI_IF_CFG_MIPI_IF_CSI; + cfg |= SUN6I_CSI_IF_CFG_IF_CSI; flags = endpoint->bus.parallel.flags; - cfg |= (bus_width == 16) ? CSI_IF_CFG_CSI_IF_YUV422_16BIT : - CSI_IF_CFG_CSI_IF_YUV422_INTLV; + if (bus_width == 16) + cfg |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_COMBINED; + else + cfg |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_RAW; if (flags & V4L2_MBUS_FIELD_EVEN_LOW) - cfg |= CSI_IF_CFG_FIELD_POSITIVE; + cfg |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE; + else + cfg |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE; if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - cfg |= CSI_IF_CFG_VREF_POL_POSITIVE; + cfg |= SUN6I_CSI_IF_CFG_VREF_POL_NEGATIVE; + else + cfg |= SUN6I_CSI_IF_CFG_VREF_POL_POSITIVE; + if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - cfg |= CSI_IF_CFG_HREF_POL_POSITIVE; + cfg |= SUN6I_CSI_IF_CFG_HREF_POL_NEGATIVE; + else + cfg |= SUN6I_CSI_IF_CFG_HREF_POL_POSITIVE; if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) - cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE; + cfg |= SUN6I_CSI_IF_CFG_CLK_POL_RISING; + else + cfg |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING; break; case V4L2_MBUS_BT656: - cfg |= CSI_IF_CFG_MIPI_IF_CSI; + cfg |= SUN6I_CSI_IF_CFG_IF_CSI; flags = endpoint->bus.parallel.flags; - cfg |= (bus_width == 16) ? CSI_IF_CFG_CSI_IF_BT1120 : - CSI_IF_CFG_CSI_IF_BT656; + if (bus_width == 16) + cfg |= SUN6I_CSI_IF_CFG_IF_CSI_BT1120; + else + cfg |= SUN6I_CSI_IF_CFG_IF_CSI_BT656; if (flags & V4L2_MBUS_FIELD_EVEN_LOW) - cfg |= CSI_IF_CFG_FIELD_POSITIVE; + cfg |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE; + else + cfg |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE; if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) - cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE; + cfg |= SUN6I_CSI_IF_CFG_CLK_POL_RISING; + else + cfg |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING; break; default: dev_warn(csi_dev->dev, "Unsupported bus type: %d\n", @@ -399,13 +412,13 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_device *csi_dev) switch (bus_width) { case 8: - cfg |= CSI_IF_CFG_IF_DATA_WIDTH_8BIT; + cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_8; break; case 10: - cfg |= CSI_IF_CFG_IF_DATA_WIDTH_10BIT; + cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_10; break; case 12: - cfg |= CSI_IF_CFG_IF_DATA_WIDTH_12BIT; + cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_12; break; case 16: /* No need to configure DATA_WIDTH for 16bit */ break; @@ -414,42 +427,35 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_device *csi_dev) break; } - regmap_write(csi_dev->regmap, CSI_IF_CFG_REG, cfg); + regmap_write(csi_dev->regmap, SUN6I_CSI_IF_CFG_REG, cfg); } static void sun6i_csi_set_format(struct sun6i_csi_device *csi_dev) { struct sun6i_csi_config *config = &csi_dev->config; - u32 cfg; + u32 cfg = 0; u32 val; - regmap_read(csi_dev->regmap, CSI_CH_CFG_REG, &cfg); - - cfg &= ~(CSI_CH_CFG_INPUT_FMT_MASK | - CSI_CH_CFG_OUTPUT_FMT_MASK | CSI_CH_CFG_VFLIP_EN | - CSI_CH_CFG_HFLIP_EN | CSI_CH_CFG_FIELD_SEL_MASK | - CSI_CH_CFG_INPUT_SEQ_MASK); - val = get_csi_input_format(csi_dev, config->code, config->pixelformat); - cfg |= CSI_CH_CFG_INPUT_FMT(val); + cfg |= SUN6I_CSI_CH_CFG_INPUT_FMT(val); val = get_csi_output_format(csi_dev, config->pixelformat, config->field); - cfg |= CSI_CH_CFG_OUTPUT_FMT(val); + cfg |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(val); val = get_csi_input_seq(csi_dev, config->code, config->pixelformat); - cfg |= CSI_CH_CFG_INPUT_SEQ(val); + cfg |= SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(val); if (config->field == V4L2_FIELD_TOP) - cfg |= CSI_CH_CFG_FIELD_SEL_FIELD0; + cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD0; else if (config->field == V4L2_FIELD_BOTTOM) - cfg |= CSI_CH_CFG_FIELD_SEL_FIELD1; + cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD1; else - cfg |= CSI_CH_CFG_FIELD_SEL_BOTH; + cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_EITHER; - regmap_write(csi_dev->regmap, CSI_CH_CFG_REG, cfg); + regmap_write(csi_dev->regmap, SUN6I_CSI_CH_CFG_REG, cfg); } static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev) @@ -475,12 +481,12 @@ static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev) break; } - regmap_write(csi_dev->regmap, CSI_CH_HSIZE_REG, - CSI_CH_HSIZE_HOR_LEN(hor_len) | - CSI_CH_HSIZE_HOR_START(0)); - regmap_write(csi_dev->regmap, CSI_CH_VSIZE_REG, - CSI_CH_VSIZE_VER_LEN(height) | - CSI_CH_VSIZE_VER_START(0)); + regmap_write(csi_dev->regmap, SUN6I_CSI_CH_HSIZE_REG, + SUN6I_CSI_CH_HSIZE_LEN(hor_len) | + SUN6I_CSI_CH_HSIZE_START(0)); + regmap_write(csi_dev->regmap, SUN6I_CSI_CH_VSIZE_REG, + SUN6I_CSI_CH_VSIZE_LEN(height) | + SUN6I_CSI_CH_VSIZE_START(0)); planar_offset[0] = 0; switch (config->pixelformat) { @@ -521,9 +527,9 @@ static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev) break; } - regmap_write(csi_dev->regmap, CSI_CH_BUF_LEN_REG, - CSI_CH_BUF_LEN_BUF_LEN_C(bytesperline_c) | - CSI_CH_BUF_LEN_BUF_LEN_Y(bytesperline_y)); + regmap_write(csi_dev->regmap, SUN6I_CSI_CH_BUF_LEN_REG, + SUN6I_CSI_CH_BUF_LEN_CHROMA_LINE(bytesperline_c) | + SUN6I_CSI_CH_BUF_LEN_LUMA_LINE(bytesperline_y)); } int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev, @@ -544,14 +550,16 @@ int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev, void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev, dma_addr_t addr) { - regmap_write(csi_dev->regmap, CSI_CH_F0_BUFA_REG, - (addr + csi_dev->planar_offset[0]) >> 2); + regmap_write(csi_dev->regmap, SUN6I_CSI_CH_FIFO0_ADDR_REG, + SUN6I_CSI_ADDR_VALUE(addr + csi_dev->planar_offset[0])); if (csi_dev->planar_offset[1] != -1) - regmap_write(csi_dev->regmap, CSI_CH_F1_BUFA_REG, - (addr + csi_dev->planar_offset[1]) >> 2); + regmap_write(csi_dev->regmap, SUN6I_CSI_CH_FIFO1_ADDR_REG, + SUN6I_CSI_ADDR_VALUE(addr + + csi_dev->planar_offset[1])); if (csi_dev->planar_offset[2] != -1) - regmap_write(csi_dev->regmap, CSI_CH_F2_BUFA_REG, - (addr + csi_dev->planar_offset[2]) >> 2); + regmap_write(csi_dev->regmap, SUN6I_CSI_CH_FIFO2_ADDR_REG, + SUN6I_CSI_ADDR_VALUE(addr + + csi_dev->planar_offset[2])); } void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable) @@ -559,23 +567,25 @@ void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable) struct regmap *regmap = csi_dev->regmap; if (!enable) { - regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON, 0); - regmap_write(regmap, CSI_CH_INT_EN_REG, 0); + regmap_update_bits(regmap, SUN6I_CSI_CAP_REG, + SUN6I_CSI_CAP_VCAP_ON, 0); + regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, 0); return; } - regmap_write(regmap, CSI_CH_INT_STA_REG, 0xFF); - regmap_write(regmap, CSI_CH_INT_EN_REG, - CSI_CH_INT_EN_VS_INT_EN | - CSI_CH_INT_EN_HB_OF_INT_EN | - CSI_CH_INT_EN_FIFO2_OF_INT_EN | - CSI_CH_INT_EN_FIFO1_OF_INT_EN | - CSI_CH_INT_EN_FIFO0_OF_INT_EN | - CSI_CH_INT_EN_FD_INT_EN | - CSI_CH_INT_EN_CD_INT_EN); - - regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON, - CSI_CAP_CH0_VCAP_ON); + regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, + SUN6I_CSI_CH_INT_STA_CLEAR); + regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, + SUN6I_CSI_CH_INT_EN_VS | + SUN6I_CSI_CH_INT_EN_HB_OF | + SUN6I_CSI_CH_INT_EN_FIFO2_OF | + SUN6I_CSI_CH_INT_EN_FIFO1_OF | + SUN6I_CSI_CH_INT_EN_FIFO0_OF | + SUN6I_CSI_CH_INT_EN_FD | + SUN6I_CSI_CH_INT_EN_CD); + + regmap_update_bits(regmap, SUN6I_CSI_CAP_REG, SUN6I_CSI_CAP_VCAP_ON, + SUN6I_CSI_CAP_VCAP_ON); } /* Media */ @@ -661,29 +671,31 @@ static irqreturn_t sun6i_csi_isr(int irq, void *private) struct regmap *regmap = csi_dev->regmap; u32 status; - regmap_read(regmap, CSI_CH_INT_STA_REG, &status); + regmap_read(regmap, SUN6I_CSI_CH_INT_STA_REG, &status); if (!(status & 0xFF)) return IRQ_NONE; - if ((status & CSI_CH_INT_STA_FIFO0_OF_PD) || - (status & CSI_CH_INT_STA_FIFO1_OF_PD) || - (status & CSI_CH_INT_STA_FIFO2_OF_PD) || - (status & CSI_CH_INT_STA_HB_OF_PD)) { - regmap_write(regmap, CSI_CH_INT_STA_REG, status); - regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0); - regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, - CSI_EN_CSI_EN); + if ((status & SUN6I_CSI_CH_INT_STA_FIFO0_OF) || + (status & SUN6I_CSI_CH_INT_STA_FIFO1_OF) || + (status & SUN6I_CSI_CH_INT_STA_FIFO2_OF) || + (status & SUN6I_CSI_CH_INT_STA_HB_OF)) { + regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, status); + + regmap_update_bits(regmap, SUN6I_CSI_EN_REG, + SUN6I_CSI_EN_CSI_EN, 0); + regmap_update_bits(regmap, SUN6I_CSI_EN_REG, + SUN6I_CSI_EN_CSI_EN, SUN6I_CSI_EN_CSI_EN); return IRQ_HANDLED; } - if (status & CSI_CH_INT_STA_FD_PD) + if (status & SUN6I_CSI_CH_INT_STA_FD) sun6i_csi_capture_frame_done(csi_dev); - if (status & CSI_CH_INT_STA_VS_PD) + if (status & SUN6I_CSI_CH_INT_STA_VS) sun6i_csi_capture_sync(csi_dev); - regmap_write(regmap, CSI_CH_INT_STA_REG, status); + regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, status); return IRQ_HANDLED; } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h index 703fa14bb313..9b0326d6ba3c 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h @@ -10,133 +10,175 @@ #include -#define CSI_EN_REG 0x0 -#define CSI_EN_VER_EN BIT(30) -#define CSI_EN_CSI_EN BIT(0) - -#define CSI_IF_CFG_REG 0x4 -#define CSI_IF_CFG_SRC_TYPE_MASK BIT(21) -#define CSI_IF_CFG_SRC_TYPE_PROGRESSED ((0 << 21) & CSI_IF_CFG_SRC_TYPE_MASK) -#define CSI_IF_CFG_SRC_TYPE_INTERLACED ((1 << 21) & CSI_IF_CFG_SRC_TYPE_MASK) -#define CSI_IF_CFG_FPS_DS_EN BIT(20) -#define CSI_IF_CFG_FIELD_MASK BIT(19) -#define CSI_IF_CFG_FIELD_NEGATIVE ((0 << 19) & CSI_IF_CFG_FIELD_MASK) -#define CSI_IF_CFG_FIELD_POSITIVE ((1 << 19) & CSI_IF_CFG_FIELD_MASK) -#define CSI_IF_CFG_VREF_POL_MASK BIT(18) -#define CSI_IF_CFG_VREF_POL_NEGATIVE ((0 << 18) & CSI_IF_CFG_VREF_POL_MASK) -#define CSI_IF_CFG_VREF_POL_POSITIVE ((1 << 18) & CSI_IF_CFG_VREF_POL_MASK) -#define CSI_IF_CFG_HREF_POL_MASK BIT(17) -#define CSI_IF_CFG_HREF_POL_NEGATIVE ((0 << 17) & CSI_IF_CFG_HREF_POL_MASK) -#define CSI_IF_CFG_HREF_POL_POSITIVE ((1 << 17) & CSI_IF_CFG_HREF_POL_MASK) -#define CSI_IF_CFG_CLK_POL_MASK BIT(16) -#define CSI_IF_CFG_CLK_POL_RISING_EDGE ((0 << 16) & CSI_IF_CFG_CLK_POL_MASK) -#define CSI_IF_CFG_CLK_POL_FALLING_EDGE ((1 << 16) & CSI_IF_CFG_CLK_POL_MASK) -#define CSI_IF_CFG_IF_DATA_WIDTH_MASK GENMASK(10, 8) -#define CSI_IF_CFG_IF_DATA_WIDTH_8BIT ((0 << 8) & CSI_IF_CFG_IF_DATA_WIDTH_MASK) -#define CSI_IF_CFG_IF_DATA_WIDTH_10BIT ((1 << 8) & CSI_IF_CFG_IF_DATA_WIDTH_MASK) -#define CSI_IF_CFG_IF_DATA_WIDTH_12BIT ((2 << 8) & CSI_IF_CFG_IF_DATA_WIDTH_MASK) -#define CSI_IF_CFG_MIPI_IF_MASK BIT(7) -#define CSI_IF_CFG_MIPI_IF_CSI (0 << 7) -#define CSI_IF_CFG_MIPI_IF_MIPI BIT(7) -#define CSI_IF_CFG_CSI_IF_MASK GENMASK(4, 0) -#define CSI_IF_CFG_CSI_IF_YUV422_INTLV ((0 << 0) & CSI_IF_CFG_CSI_IF_MASK) -#define CSI_IF_CFG_CSI_IF_YUV422_16BIT ((1 << 0) & CSI_IF_CFG_CSI_IF_MASK) -#define CSI_IF_CFG_CSI_IF_BT656 ((4 << 0) & CSI_IF_CFG_CSI_IF_MASK) -#define CSI_IF_CFG_CSI_IF_BT1120 ((5 << 0) & CSI_IF_CFG_CSI_IF_MASK) - -#define CSI_CAP_REG 0x8 -#define CSI_CAP_CH0_CAP_MASK_MASK GENMASK(5, 2) -#define CSI_CAP_CH0_CAP_MASK(count) (((count) << 2) & CSI_CAP_CH0_CAP_MASK_MASK) -#define CSI_CAP_CH0_VCAP_ON BIT(1) -#define CSI_CAP_CH0_SCAP_ON BIT(0) - -#define CSI_SYNC_CNT_REG 0xc -#define CSI_FIFO_THRS_REG 0x10 -#define CSI_BT656_HEAD_CFG_REG 0x14 -#define CSI_PTN_LEN_REG 0x30 -#define CSI_PTN_ADDR_REG 0x34 -#define CSI_VER_REG 0x3c - -#define CSI_CH_CFG_REG 0x44 -#define CSI_CH_CFG_INPUT_FMT_MASK GENMASK(23, 20) -#define CSI_CH_CFG_INPUT_FMT(fmt) (((fmt) << 20) & CSI_CH_CFG_INPUT_FMT_MASK) -#define CSI_CH_CFG_OUTPUT_FMT_MASK GENMASK(19, 16) -#define CSI_CH_CFG_OUTPUT_FMT(fmt) (((fmt) << 16) & CSI_CH_CFG_OUTPUT_FMT_MASK) -#define CSI_CH_CFG_VFLIP_EN BIT(13) -#define CSI_CH_CFG_HFLIP_EN BIT(12) -#define CSI_CH_CFG_FIELD_SEL_MASK GENMASK(11, 10) -#define CSI_CH_CFG_FIELD_SEL_FIELD0 ((0 << 10) & CSI_CH_CFG_FIELD_SEL_MASK) -#define CSI_CH_CFG_FIELD_SEL_FIELD1 ((1 << 10) & CSI_CH_CFG_FIELD_SEL_MASK) -#define CSI_CH_CFG_FIELD_SEL_BOTH ((2 << 10) & CSI_CH_CFG_FIELD_SEL_MASK) -#define CSI_CH_CFG_INPUT_SEQ_MASK GENMASK(9, 8) -#define CSI_CH_CFG_INPUT_SEQ(seq) (((seq) << 8) & CSI_CH_CFG_INPUT_SEQ_MASK) - -#define CSI_CH_SCALE_REG 0x4c -#define CSI_CH_SCALE_QUART_EN BIT(0) - -#define CSI_CH_F0_BUFA_REG 0x50 - -#define CSI_CH_F1_BUFA_REG 0x58 - -#define CSI_CH_F2_BUFA_REG 0x60 - -#define CSI_CH_STA_REG 0x6c -#define CSI_CH_STA_FIELD_STA_MASK BIT(2) -#define CSI_CH_STA_FIELD_STA_FIELD0 ((0 << 2) & CSI_CH_STA_FIELD_STA_MASK) -#define CSI_CH_STA_FIELD_STA_FIELD1 ((1 << 2) & CSI_CH_STA_FIELD_STA_MASK) -#define CSI_CH_STA_VCAP_STA BIT(1) -#define CSI_CH_STA_SCAP_STA BIT(0) - -#define CSI_CH_INT_EN_REG 0x70 -#define CSI_CH_INT_EN_VS_INT_EN BIT(7) -#define CSI_CH_INT_EN_HB_OF_INT_EN BIT(6) -#define CSI_CH_INT_EN_MUL_ERR_INT_EN BIT(5) -#define CSI_CH_INT_EN_FIFO2_OF_INT_EN BIT(4) -#define CSI_CH_INT_EN_FIFO1_OF_INT_EN BIT(3) -#define CSI_CH_INT_EN_FIFO0_OF_INT_EN BIT(2) -#define CSI_CH_INT_EN_FD_INT_EN BIT(1) -#define CSI_CH_INT_EN_CD_INT_EN BIT(0) - -#define CSI_CH_INT_STA_REG 0x74 -#define CSI_CH_INT_STA_VS_PD BIT(7) -#define CSI_CH_INT_STA_HB_OF_PD BIT(6) -#define CSI_CH_INT_STA_MUL_ERR_PD BIT(5) -#define CSI_CH_INT_STA_FIFO2_OF_PD BIT(4) -#define CSI_CH_INT_STA_FIFO1_OF_PD BIT(3) -#define CSI_CH_INT_STA_FIFO0_OF_PD BIT(2) -#define CSI_CH_INT_STA_FD_PD BIT(1) -#define CSI_CH_INT_STA_CD_PD BIT(0) - -#define CSI_CH_FLD1_VSIZE_REG 0x78 - -#define CSI_CH_HSIZE_REG 0x80 -#define CSI_CH_HSIZE_HOR_LEN_MASK GENMASK(28, 16) -#define CSI_CH_HSIZE_HOR_LEN(len) (((len) << 16) & CSI_CH_HSIZE_HOR_LEN_MASK) -#define CSI_CH_HSIZE_HOR_START_MASK GENMASK(12, 0) -#define CSI_CH_HSIZE_HOR_START(start) (((start) << 0) & CSI_CH_HSIZE_HOR_START_MASK) - -#define CSI_CH_VSIZE_REG 0x84 -#define CSI_CH_VSIZE_VER_LEN_MASK GENMASK(28, 16) -#define CSI_CH_VSIZE_VER_LEN(len) (((len) << 16) & CSI_CH_VSIZE_VER_LEN_MASK) -#define CSI_CH_VSIZE_VER_START_MASK GENMASK(12, 0) -#define CSI_CH_VSIZE_VER_START(start) (((start) << 0) & CSI_CH_VSIZE_VER_START_MASK) - -#define CSI_CH_BUF_LEN_REG 0x88 -#define CSI_CH_BUF_LEN_BUF_LEN_C_MASK GENMASK(29, 16) -#define CSI_CH_BUF_LEN_BUF_LEN_C(len) (((len) << 16) & CSI_CH_BUF_LEN_BUF_LEN_C_MASK) -#define CSI_CH_BUF_LEN_BUF_LEN_Y_MASK GENMASK(13, 0) -#define CSI_CH_BUF_LEN_BUF_LEN_Y(len) (((len) << 0) & CSI_CH_BUF_LEN_BUF_LEN_Y_MASK) - -#define CSI_CH_FLIP_SIZE_REG 0x8c -#define CSI_CH_FLIP_SIZE_VER_LEN_MASK GENMASK(28, 16) -#define CSI_CH_FLIP_SIZE_VER_LEN(len) (((len) << 16) & CSI_CH_FLIP_SIZE_VER_LEN_MASK) -#define CSI_CH_FLIP_SIZE_VALID_LEN_MASK GENMASK(12, 0) -#define CSI_CH_FLIP_SIZE_VALID_LEN(len) (((len) << 0) & CSI_CH_FLIP_SIZE_VALID_LEN_MASK) - -#define CSI_CH_FRM_CLK_CNT_REG 0x90 -#define CSI_CH_ACC_ITNL_CLK_CNT_REG 0x94 -#define CSI_CH_FIFO_STAT_REG 0x98 -#define CSI_CH_PCLK_STAT_REG 0x9c +#define SUN6I_CSI_ADDR_VALUE(a) ((a) >> 2) + +#define SUN6I_CSI_EN_REG 0x0 +#define SUN6I_CSI_EN_VER_EN BIT(30) +#define SUN6I_CSI_EN_PTN_CYCLE(v) (((v) << 16) & GENMASK(23, 16)) +#define SUN6I_CSI_EN_SRAM_PWDN BIT(8) +#define SUN6I_CSI_EN_PTN_START BIT(4) +#define SUN6I_CSI_EN_CLK_CNT_SPL_VSYNC BIT(3) +#define SUN6I_CSI_EN_CLK_CNT_EN BIT(2) +#define SUN6I_CSI_EN_PTN_GEN_EN BIT(1) +#define SUN6I_CSI_EN_CSI_EN BIT(0) + +/* Note that Allwinner manuals and code invert positive/negative definitions. */ + +#define SUN6I_CSI_IF_CFG_REG 0x4 +#define SUN6I_CSI_IF_CFG_FIELD_DT_PCLK_SHIFT(v) (((v) << 24) & GENMASK(27, 24)) +#define SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE (0 << 21) +#define SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED (1 << 21) +#define SUN6I_CSI_IF_CFG_FPS_DS BIT(20) +#define SUN6I_CSI_IF_CFG_FIELD_POSITIVE (0 << 19) +#define SUN6I_CSI_IF_CFG_FIELD_NEGATIVE (1 << 19) +#define SUN6I_CSI_IF_CFG_VREF_POL_POSITIVE (0 << 18) +#define SUN6I_CSI_IF_CFG_VREF_POL_NEGATIVE (1 << 18) +#define SUN6I_CSI_IF_CFG_HREF_POL_POSITIVE (0 << 17) +#define SUN6I_CSI_IF_CFG_HREF_POL_NEGATIVE (1 << 17) +#define SUN6I_CSI_IF_CFG_CLK_POL_FALLING (0 << 16) +#define SUN6I_CSI_IF_CFG_CLK_POL_RISING (1 << 16) +#define SUN6I_CSI_IF_CFG_FIELD_DT_FIELD_VSYNC (0 << 14) +#define SUN6I_CSI_IF_CFG_FIELD_DT_FIELD (1 << 14) +#define SUN6I_CSI_IF_CFG_FIELD_DT_VSYNC (2 << 14) +#define SUN6I_CSI_IF_CFG_DATA_WIDTH_8 (0 << 8) +#define SUN6I_CSI_IF_CFG_DATA_WIDTH_10 (1 << 8) +#define SUN6I_CSI_IF_CFG_DATA_WIDTH_12 (2 << 8) +#define SUN6I_CSI_IF_CFG_DATA_WIDTH_8_PLUS_2 (3 << 8) +#define SUN6I_CSI_IF_CFG_DATA_WIDTH_2_TIMES_8 (4 << 8) +#define SUN6I_CSI_IF_CFG_IF_CSI (0 << 7) +#define SUN6I_CSI_IF_CFG_IF_MIPI (1 << 7) +#define SUN6I_CSI_IF_CFG_IF_CSI_YUV_RAW (0 << 0) +#define SUN6I_CSI_IF_CFG_IF_CSI_YUV_COMBINED (1 << 0) +#define SUN6I_CSI_IF_CFG_IF_CSI_BT656 (4 << 0) +#define SUN6I_CSI_IF_CFG_IF_CSI_BT1120 (5 << 0) + +#define SUN6I_CSI_CAP_REG 0x8 +#define SUN6I_CSI_CAP_MASK(v) (((v) << 2) & GENMASK(5, 2)) +#define SUN6I_CSI_CAP_VCAP_ON BIT(1) +#define SUN6I_CSI_CAP_SCAP_ON BIT(0) + +#define SUN6I_CSI_SYNC_CNT_REG 0xc +#define SUN6I_CSI_FIFO_THRS_REG 0x10 +#define SUN6I_CSI_BT656_HEAD_CFG_REG 0x14 + +#define SUN6I_CSI_PTN_LEN_REG 0x30 +#define SUN6I_CSI_PTN_ADDR_REG 0x34 +#define SUN6I_CSI_VER_REG 0x3c + +#define SUN6I_CSI_CH_CFG_REG 0x44 +#define SUN6I_CSI_CH_CFG_PAD_VAL(v) (((v) << 24) & GENMASK(31, 24)) +#define SUN6I_CSI_CH_CFG_INPUT_FMT(v) (((v) << 20) & GENMASK(23, 20)) +#define SUN6I_CSI_CH_CFG_OUTPUT_FMT(v) (((v) << 16) & GENMASK(19, 16)) +#define SUN6I_CSI_CH_CFG_VFLIP_EN BIT(13) +#define SUN6I_CSI_CH_CFG_HFLIP_EN BIT(12) +#define SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD0 (0 << 10) +#define SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD1 (1 << 10) +#define SUN6I_CSI_CH_CFG_FIELD_SEL_EITHER (2 << 10) +#define SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(v) (((v) << 8) & GENMASK(9, 8)) + +#define SUN6I_CSI_INPUT_FMT_RAW 0 +#define SUN6I_CSI_INPUT_FMT_YUV422 3 +#define SUN6I_CSI_INPUT_FMT_YUV420 4 + +/* Note that Allwinner manuals and code invert frame/field definitions. */ + +/* RAW */ +#define SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8 0 +#define SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10 1 +#define SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12 2 +#define SUN6I_CSI_OUTPUT_FMT_FRAME_RGB565 4 +#define SUN6I_CSI_OUTPUT_FMT_FRAME_RGB888 5 +#define SUN6I_CSI_OUTPUT_FMT_FRAME_PRGB888 6 +#define SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8 8 +#define SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10 9 +#define SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12 10 +#define SUN6I_CSI_OUTPUT_FMT_FIELD_RGB565 12 +#define SUN6I_CSI_OUTPUT_FMT_FIELD_RGB888 13 +#define SUN6I_CSI_OUTPUT_FMT_FIELD_PRGB888 14 + +/* YUV */ +#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422P 0 +#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420P 1 +#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420P 2 +#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422P 3 +#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422SP 4 +#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420SP 5 +#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420SP 6 +#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422SP 7 +#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422MB 8 +#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420MB 9 +#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420MB 10 +#define SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422MB 11 +#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422SP_10 12 +#define SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420SP_10 13 + +/* YUV Planar */ +#define SUN6I_CSI_INPUT_YUV_SEQ_YUYV 0 +#define SUN6I_CSI_INPUT_YUV_SEQ_YVYU 1 +#define SUN6I_CSI_INPUT_YUV_SEQ_UYVY 2 +#define SUN6I_CSI_INPUT_YUV_SEQ_VYUY 3 + +/* YUV Semi-planar */ +#define SUN6I_CSI_INPUT_YUV_SEQ_UV 0 +#define SUN6I_CSI_INPUT_YUV_SEQ_VU 1 + +#define SUN6I_CSI_CH_SCALE_REG 0x4c +#define SUN6I_CSI_CH_SCALE_QUART_EN BIT(0) + +#define SUN6I_CSI_CH_FIFO0_ADDR_REG 0x50 +#define SUN6I_CSI_CH_FIFO1_ADDR_REG 0x58 +#define SUN6I_CSI_CH_FIFO2_ADDR_REG 0x60 + +#define SUN6I_CSI_CH_STA_REG 0x6c +#define SUN6I_CSI_CH_STA_FIELD BIT(2) +#define SUN6I_CSI_CH_STA_VCAP BIT(1) +#define SUN6I_CSI_CH_STA_SCAP BIT(0) + +#define SUN6I_CSI_CH_INT_EN_REG 0x70 +#define SUN6I_CSI_CH_INT_EN_VS BIT(7) +#define SUN6I_CSI_CH_INT_EN_HB_OF BIT(6) +#define SUN6I_CSI_CH_INT_EN_MUL_ERR BIT(5) +#define SUN6I_CSI_CH_INT_EN_FIFO2_OF BIT(4) +#define SUN6I_CSI_CH_INT_EN_FIFO1_OF BIT(3) +#define SUN6I_CSI_CH_INT_EN_FIFO0_OF BIT(2) +#define SUN6I_CSI_CH_INT_EN_FD BIT(1) +#define SUN6I_CSI_CH_INT_EN_CD BIT(0) + +#define SUN6I_CSI_CH_INT_STA_REG 0x74 +#define SUN6I_CSI_CH_INT_STA_CLEAR 0xff +#define SUN6I_CSI_CH_INT_STA_VS BIT(7) +#define SUN6I_CSI_CH_INT_STA_HB_OF BIT(6) +#define SUN6I_CSI_CH_INT_STA_MUL_ERR BIT(5) +#define SUN6I_CSI_CH_INT_STA_FIFO2_OF BIT(4) +#define SUN6I_CSI_CH_INT_STA_FIFO1_OF BIT(3) +#define SUN6I_CSI_CH_INT_STA_FIFO0_OF BIT(2) +#define SUN6I_CSI_CH_INT_STA_FD BIT(1) +#define SUN6I_CSI_CH_INT_STA_CD BIT(0) + +#define SUN6I_CSI_CH_FLD1_VSIZE_REG 0x78 +#define SUN6I_CSI_CH_FLD1_VSIZE_VER_LEN(v) (((v) << 16) & GENMASK(28, 16)) +#define SUN6I_CSI_CH_FLD1_VSIZE_VER_START(v) ((v) & GENMASK(12, 0)) + +#define SUN6I_CSI_CH_HSIZE_REG 0x80 +#define SUN6I_CSI_CH_HSIZE_LEN(v) (((v) << 16) & GENMASK(28, 16)) +#define SUN6I_CSI_CH_HSIZE_START(v) ((v) & GENMASK(12, 0)) + +#define SUN6I_CSI_CH_VSIZE_REG 0x84 +#define SUN6I_CSI_CH_VSIZE_LEN(v) (((v) << 16) & GENMASK(28, 16)) +#define SUN6I_CSI_CH_VSIZE_START(v) ((v) & GENMASK(12, 0)) + +#define SUN6I_CSI_CH_BUF_LEN_REG 0x88 +#define SUN6I_CSI_CH_BUF_LEN_CHROMA_LINE(v) (((v) << 16) & GENMASK(29, 16)) +#define SUN6I_CSI_CH_BUF_LEN_LUMA_LINE(v) ((v) & GENMASK(13, 0)) + +#define SUN6I_CSI_CH_FLIP_SIZE_REG 0x8c +#define SUN6I_CSI_CH_FLIP_SIZE_VER_LEN(v) (((v) << 16) & GENMASK(28, 16)) +#define SUN6I_CSI_CH_FLIP_SIZE_VALID_LEN(v) ((v) & GENMASK(12, 0)) + +#define SUN6I_CSI_CH_FRM_CLK_CNT_REG 0x90 +#define SUN6I_CSI_CH_ACC_ITNL_CLK_CNT_REG 0x94 +#define SUN6I_CSI_CH_FIFO_STAT_REG 0x98 +#define SUN6I_CSI_CH_PCLK_STAT_REG 0x9c /* * csi input data format From patchwork Fri Mar 11 14:35:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778122 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CD7D3C433EF for ; Fri, 11 Mar 2022 14:36:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349570AbiCKOhh (ORCPT ); Fri, 11 Mar 2022 09:37:37 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59154 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349533AbiCKOhb (ORCPT ); Fri, 11 Mar 2022 09:37:31 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 74E031C947D; Fri, 11 Mar 2022 06:36:21 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 0BE3124000C; Fri, 11 Mar 2022 14:36:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009380; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=MKmJo4pe35t5EXt9jJlqCaZhlnGKEm842sgyp4ZOkT0=; b=RFYYRITvxOczB2KRHmonjhCranHCDOSKzZBA8/36CLahhSsSZFtgaC9APsBo68fI0DFhmw MjU02pPnjGKeMrqph8BYReSS10yewrlkl2x47f5ufq4dii0uRmbo+xPr69jU6XHPnm6lu5 +t7tOry3rM4gS1GwPzv7DjuykVb76f94iGqrlFPnmxgeyIsiyQ8TjNNXz9RUYpaUfUjcDV tj9fRyC9kkAnIk/MS6OZPhPmIrb5irB6AYJtnF9cqMZBtW/JQ3cCPnJzH+0I8c/arpBHw2 0m1A3XUiRbwT487pD7ic6F0CFvtGV245hzYkOSXo8kV8ecXhVDkOGm85LCAhCQ== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 20/46] media: sun6i-csi: Add dimensions and format helpers to capture Date: Fri, 11 Mar 2022 15:35:06 +0100 Message-Id: <20220311143532.265091-21-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Define and export useful helpers to access dimensions and pixel format. Signed-off-by: Paul Kocialkowski --- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 19 +++++++++++++++++++ .../sunxi/sun6i-csi/sun6i_csi_capture.h | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index bcbb4ffbb517..7b8556a25c61 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -25,6 +25,25 @@ /* Helpers */ +void sun6i_csi_capture_dimensions(struct sun6i_csi_device *csi_dev, + unsigned int *width, unsigned int *height) +{ + if (width) + *width = csi_dev->capture.format.fmt.pix.width; + if (height) + *height = csi_dev->capture.format.fmt.pix.height; +} + +void sun6i_csi_capture_format(struct sun6i_csi_device *csi_dev, + u32 *pixelformat, u32 *field) +{ + if (pixelformat) + *pixelformat = csi_dev->capture.format.fmt.pix.pixelformat; + + if (field) + *field = csi_dev->capture.format.fmt.pix.field; +} + static struct v4l2_subdev * sun6i_csi_capture_remote_subdev(struct sun6i_csi_capture *capture, u32 *pad) { diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h index 7fa66a2af5ec..935f35b7049a 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h @@ -37,6 +37,11 @@ struct sun6i_csi_capture { u32 mbus_code; }; +void sun6i_csi_capture_dimensions(struct sun6i_csi_device *csi_dev, + unsigned int *width, unsigned int *height); +void sun6i_csi_capture_format(struct sun6i_csi_device *csi_dev, + u32 *pixelformat, u32 *field); + void sun6i_csi_capture_sync(struct sun6i_csi_device *csi_dev); void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev); From patchwork Fri Mar 11 14:35:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778124 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1C1D6C433EF for ; Fri, 11 Mar 2022 14:36:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349575AbiCKOhk (ORCPT ); Fri, 11 Mar 2022 09:37:40 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59468 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349546AbiCKOhb (ORCPT ); Fri, 11 Mar 2022 09:37:31 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 59CE41C9B67; Fri, 11 Mar 2022 06:36:23 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 484A0240013; Fri, 11 Mar 2022 14:36:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009381; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=4PUV78OOO2BVTDPi6NQ/HNVyH5z46hC+t0Sj6lFzABA=; b=HQQBTpptpHxfjmY/9Dp+DAhMMVFwY3TcgMEwdDEaj9BCvH1jKnDjQAoKY94xm7GG+ZQvvi 3AlyX/vS6xTZNA/lRkQSYLxIcRCcHGhx1R41sEhTa9qQmAheM4SmXmTZUOJ+9FAiVGk9eG TlHiqWEcjnQt2/mM7ayInvMsIn+SRtUkptvASQVh8XN/1xXp/RyY3+1Yf4qqAJLoFVSUOF X816iexYO6Zo+XOlM+hbdvGy0usPpYsbkgsoB7fSH0804ViHMsFMHoZnx79gvfg7lFhKoM KTVkaIa0YXIBJbfTtNrCxdyQCaNZgmdn8/7uBN5sl9qTVTH9bQ0+ulI4NvxGPA== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 21/46] media: sun6i-csi: Implement address configuration without indirection Date: Fri, 11 Mar 2022 15:35:07 +0100 Message-Id: <20220311143532.265091-22-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Instead of calculating the planar_offset at one point and using it later in a dedicated function, reimplement address configuration with v4l2 format info in the buffer_configure function. Signed-off-by: Paul Kocialkowski --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 27 ---------------- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 10 ------ .../sunxi/sun6i-csi/sun6i_csi_capture.c | 32 ++++++++++++++++++- 3 files changed, 31 insertions(+), 38 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index d0f08173d6ad..b18c7c2d9bad 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -463,7 +463,6 @@ static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev) struct sun6i_csi_config *config = &csi_dev->config; u32 bytesperline_y; u32 bytesperline_c; - int *planar_offset = csi_dev->planar_offset; u32 width = config->width; u32 height = config->height; u32 hor_len = width; @@ -488,7 +487,6 @@ static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev) SUN6I_CSI_CH_VSIZE_LEN(height) | SUN6I_CSI_CH_VSIZE_START(0)); - planar_offset[0] = 0; switch (config->pixelformat) { case V4L2_PIX_FMT_NV12_16L16: case V4L2_PIX_FMT_NV12: @@ -497,23 +495,15 @@ static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev) case V4L2_PIX_FMT_NV61: bytesperline_y = width; bytesperline_c = width; - planar_offset[1] = bytesperline_y * height; - planar_offset[2] = -1; break; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: bytesperline_y = width; bytesperline_c = width / 2; - planar_offset[1] = bytesperline_y * height; - planar_offset[2] = planar_offset[1] + - bytesperline_c * height / 2; break; case V4L2_PIX_FMT_YUV422P: bytesperline_y = width; bytesperline_c = width / 2; - planar_offset[1] = bytesperline_y * height; - planar_offset[2] = planar_offset[1] + - bytesperline_c * height; break; default: /* raw */ dev_dbg(csi_dev->dev, @@ -522,8 +512,6 @@ static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev) bytesperline_y = (sun6i_csi_get_bpp(config->pixelformat) * config->width) / 8; bytesperline_c = 0; - planar_offset[1] = -1; - planar_offset[2] = -1; break; } @@ -547,21 +535,6 @@ int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev, return 0; } -void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev, - dma_addr_t addr) -{ - regmap_write(csi_dev->regmap, SUN6I_CSI_CH_FIFO0_ADDR_REG, - SUN6I_CSI_ADDR_VALUE(addr + csi_dev->planar_offset[0])); - if (csi_dev->planar_offset[1] != -1) - regmap_write(csi_dev->regmap, SUN6I_CSI_CH_FIFO1_ADDR_REG, - SUN6I_CSI_ADDR_VALUE(addr + - csi_dev->planar_offset[1])); - if (csi_dev->planar_offset[2] != -1) - regmap_write(csi_dev->regmap, SUN6I_CSI_CH_FIFO2_ADDR_REG, - SUN6I_CSI_ADDR_VALUE(addr + - csi_dev->planar_offset[2])); -} - void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable) { struct regmap *regmap = csi_dev->regmap; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index b7e51447accb..8b85de79996e 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -63,8 +63,6 @@ struct sun6i_csi_device { struct clk *clk_mod; struct clk *clk_ram; struct reset_control *reset; - - int planar_offset[3]; }; struct sun6i_csi_variant { @@ -95,14 +93,6 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable); int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev, struct sun6i_csi_config *config); -/** - * sun6i_csi_update_buf_addr() - update the csi frame buffer address - * @csi: pointer to the csi - * @addr: frame buffer's physical address - */ -void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev, - dma_addr_t addr); - /** * sun6i_csi_set_stream() - start/stop csi streaming * @csi: pointer to the csi diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 7b8556a25c61..f32beed0aaad 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -6,6 +6,7 @@ */ #include +#include #include #include @@ -16,6 +17,7 @@ #include "sun6i_csi.h" #include "sun6i_csi_capture.h" +#include "sun6i_csi_reg.h" /* This is got from BSP sources. */ #define MIN_WIDTH (32) @@ -109,13 +111,41 @@ static void sun6i_csi_capture_buffer_configure(struct sun6i_csi_device *csi_dev, struct sun6i_csi_buffer *csi_buffer) { + struct regmap *regmap = csi_dev->regmap; + const struct v4l2_format_info *info; struct vb2_buffer *vb2_buffer; + unsigned int width, height; dma_addr_t address; + u32 pixelformat; vb2_buffer = &csi_buffer->v4l2_buffer.vb2_buf; address = vb2_dma_contig_plane_dma_addr(vb2_buffer, 0); - sun6i_csi_update_buf_addr(csi_dev, address); + regmap_write(regmap, SUN6I_CSI_CH_FIFO0_ADDR_REG, + SUN6I_CSI_ADDR_VALUE(address)); + + sun6i_csi_capture_dimensions(csi_dev, &width, &height); + sun6i_csi_capture_format(csi_dev, &pixelformat, NULL); + + info = v4l2_format_info(pixelformat); + /* Unsupported formats are single-plane, so we can stop here. */ + if (!info) + return; + + if (info->comp_planes > 1) { + address += info->bpp[0] * width * height; + + regmap_write(regmap, SUN6I_CSI_CH_FIFO1_ADDR_REG, + SUN6I_CSI_ADDR_VALUE(address)); + } + + if (info->comp_planes > 2) { + address += info->bpp[1] * DIV_ROUND_UP(width, info->hdiv) * + DIV_ROUND_UP(height, info->vdiv); + + regmap_write(regmap, SUN6I_CSI_CH_FIFO2_ADDR_REG, + SUN6I_CSI_ADDR_VALUE(address)); + } } static void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev) From patchwork Fri Mar 11 14:35:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778123 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0DECBC4332F for ; Fri, 11 Mar 2022 14:36:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344126AbiCKOhi (ORCPT ); Fri, 11 Mar 2022 09:37:38 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58794 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349544AbiCKOhb (ORCPT ); Fri, 11 Mar 2022 09:37:31 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 86D2C1C9B6C; Fri, 11 Mar 2022 06:36:24 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 9213C24000F; Fri, 11 Mar 2022 14:36:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009382; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qybDQUYypPXWVTQYNowBRUum8caa2APogskY+vPKUsc=; b=H/d2gJXCUdAbG1bNpm1EZIJdjwq1AIijpvr3laEUBHLiEzWbrnrU9ab4af1pOjdIBZ6rXC Evcy26aT2yvcxcpRkyo2pQjIsAt99CDpEA5vM7sKrWPVM1zj3iAmQlMgkLY7vlE3JVO2s0 ljOTSGLe1JSGxLja3hCWYJFccHI1sbVQqlDkA1Puu2M62XA9RR63qDOaqV5h15Asu8uOzd YD7nVBIFYPVm47fdUsPoQgnWbfAtq3OEKStmp5L0u9ITE+Q6BnleFLYXYsDlVDheihf53p R0VMMBd5vers/BFj+qjERb9Tb4xINVg7EOH1B2J0T3nuNZjsG+tWqiQKZelmQA== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 22/46] media: sun6i-csi: Split stream sequences and irq code in capture Date: Fri, 11 Mar 2022 15:35:08 +0100 Message-Id: <20220311143532.265091-23-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Create minimal helpers that split the enable/disable flow, which will make it easier to move control over to the bridge later on. Generally speaking the goal is to move register configuration to the capture code and later split it with the bridge code. Signed-off-by: Paul Kocialkowski --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 26 --------- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 7 --- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 58 ++++++++++++++++++- 3 files changed, 55 insertions(+), 36 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index b18c7c2d9bad..95db1a717236 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -535,32 +535,6 @@ int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev, return 0; } -void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable) -{ - struct regmap *regmap = csi_dev->regmap; - - if (!enable) { - regmap_update_bits(regmap, SUN6I_CSI_CAP_REG, - SUN6I_CSI_CAP_VCAP_ON, 0); - regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, 0); - return; - } - - regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, - SUN6I_CSI_CH_INT_STA_CLEAR); - regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, - SUN6I_CSI_CH_INT_EN_VS | - SUN6I_CSI_CH_INT_EN_HB_OF | - SUN6I_CSI_CH_INT_EN_FIFO2_OF | - SUN6I_CSI_CH_INT_EN_FIFO1_OF | - SUN6I_CSI_CH_INT_EN_FIFO0_OF | - SUN6I_CSI_CH_INT_EN_FD | - SUN6I_CSI_CH_INT_EN_CD); - - regmap_update_bits(regmap, SUN6I_CSI_CAP_REG, SUN6I_CSI_CAP_VCAP_ON, - SUN6I_CSI_CAP_VCAP_ON); -} - /* Media */ static const struct media_device_ops sun6i_csi_media_ops = { diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 8b85de79996e..d5e5aca08d32 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -93,13 +93,6 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable); int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev, struct sun6i_csi_config *config); -/** - * sun6i_csi_set_stream() - start/stop csi streaming - * @csi: pointer to the csi - * @enable: start/stop - */ -void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable); - /* get bpp form v4l2 pixformat */ static inline int sun6i_csi_get_bpp(unsigned int pixformat) { diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index f32beed0aaad..ab6e298864ed 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -107,6 +107,51 @@ static bool sun6i_csi_capture_format_check(u32 format) /* Capture */ +static void sun6i_csi_capture_irq_enable(struct sun6i_csi_device *csi_dev) +{ + struct regmap *regmap = csi_dev->regmap; + + regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, + SUN6I_CSI_CH_INT_EN_VS | + SUN6I_CSI_CH_INT_EN_HB_OF | + SUN6I_CSI_CH_INT_EN_FIFO2_OF | + SUN6I_CSI_CH_INT_EN_FIFO1_OF | + SUN6I_CSI_CH_INT_EN_FIFO0_OF | + SUN6I_CSI_CH_INT_EN_FD | + SUN6I_CSI_CH_INT_EN_CD); +} + +static void sun6i_csi_capture_irq_disable(struct sun6i_csi_device *csi_dev) +{ + struct regmap *regmap = csi_dev->regmap; + + regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, 0); +} + +static void sun6i_csi_capture_irq_clear(struct sun6i_csi_device *csi_dev) +{ + struct regmap *regmap = csi_dev->regmap; + + regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, 0); + regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, + SUN6I_CSI_CH_INT_STA_CLEAR); +} + +static void sun6i_csi_capture_enable(struct sun6i_csi_device *csi_dev) +{ + struct regmap *regmap = csi_dev->regmap; + + regmap_update_bits(regmap, SUN6I_CSI_CAP_REG, SUN6I_CSI_CAP_VCAP_ON, + SUN6I_CSI_CAP_VCAP_ON); +} + +static void sun6i_csi_capture_disable(struct sun6i_csi_device *csi_dev) +{ + struct regmap *regmap = csi_dev->regmap; + + regmap_update_bits(regmap, SUN6I_CSI_CAP_REG, SUN6I_CSI_CAP_VCAP_ON, 0); +} + static void sun6i_csi_capture_buffer_configure(struct sun6i_csi_device *csi_dev, struct sun6i_csi_buffer *csi_buffer) @@ -357,6 +402,10 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, goto error_media_pipeline; } + /* Clear */ + + sun6i_csi_capture_irq_clear(csi_dev); + /* Configure */ sun6i_csi_capture_configure(csi_dev); @@ -367,7 +416,8 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, /* Enable */ - sun6i_csi_set_stream(csi_dev, true); + sun6i_csi_capture_irq_enable(csi_dev); + sun6i_csi_capture_enable(csi_dev); ret = v4l2_subdev_call(subdev, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) @@ -376,7 +426,8 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, return 0; error_stream: - sun6i_csi_set_stream(csi_dev, false); + sun6i_csi_capture_disable(csi_dev); + sun6i_csi_capture_irq_disable(csi_dev); error_media_pipeline: media_pipeline_stop(&video_dev->entity); @@ -397,7 +448,8 @@ static void sun6i_csi_capture_stop_streaming(struct vb2_queue *queue) if (subdev) v4l2_subdev_call(subdev, video, s_stream, 0); - sun6i_csi_set_stream(csi_dev, false); + sun6i_csi_capture_disable(csi_dev); + sun6i_csi_capture_irq_disable(csi_dev); media_pipeline_stop(&capture->video_dev.entity); From patchwork Fri Mar 11 14:35:09 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778125 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8173AC433F5 for ; Fri, 11 Mar 2022 14:36:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349586AbiCKOhm (ORCPT ); Fri, 11 Mar 2022 09:37:42 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59474 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349553AbiCKOhb (ORCPT ); Fri, 11 Mar 2022 09:37:31 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 705971CA5C2; Fri, 11 Mar 2022 06:36:26 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 31B18240006; Fri, 11 Mar 2022 14:36:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009384; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fenyR24I3XdhTAB1Yl6dtAGu1StQFyiRpygkMRZbZsI=; b=gHZG5TuTBHJx1cPyTCYqfAdT3WTGKrofEE26YxqQKiVdFAykrlzDCnIk9qo8aXydkx1kq9 RHRYON6Ekx3Mf8rq/wbbbiZDWhKNOy1dD35K9FBWHpezhmDSckfvUDHYRYWLGm/hHu5nhH Ba2twmyf+FJJdPOwCXcOoRktq4HZDu3NqaD4M6Tn9Lf6wJaS30/zvlAtSAH5qqh3gp/q/l Sk+BUAGKyx+yumH/lJeQNIBtmSxtm6IcrkIxKylcBaX2Q8YdaCao1U+dFpQGMrPAJ9ctfB BxN1jrP4fLZuU1sh4FEpXVjOXkrC1fe2iYccEdWJuy3zSh7Rv9udL9jW8PZh9A== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 23/46] media: sun6i-csi: Move power management to runtime pm in capture Date: Fri, 11 Mar 2022 15:35:09 +0100 Message-Id: <20220311143532.265091-24-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Let's just enable the module when we start using it (at stream on) and benefit from runtime pm instead of enabling it at first open. Also reorder the call to v4l2_pipeline_pm_get. Signed-off-by: Paul Kocialkowski --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 24 ----------- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 7 ---- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 41 ++++++++++--------- 3 files changed, 22 insertions(+), 50 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 95db1a717236..aa7350170eef 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -148,30 +148,6 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev, return false; } -int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) -{ - struct device *dev = csi_dev->dev; - struct regmap *regmap = csi_dev->regmap; - int ret; - - if (!enable) { - regmap_update_bits(regmap, SUN6I_CSI_EN_REG, - SUN6I_CSI_EN_CSI_EN, 0); - pm_runtime_put(dev); - - return 0; - } - - ret = pm_runtime_resume_and_get(dev); - if (ret < 0) - return ret; - - regmap_update_bits(regmap, SUN6I_CSI_EN_REG, SUN6I_CSI_EN_CSI_EN, - SUN6I_CSI_EN_CSI_EN); - - return 0; -} - static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_device *csi_dev, u32 mbus_code, u32 pixformat) { diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index d5e5aca08d32..4a40a65cf1a2 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -78,13 +78,6 @@ struct sun6i_csi_variant { bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev, u32 pixformat, u32 mbus_code); -/** - * sun6i_csi_set_power() - power on/off the csi - * @csi: pointer to the csi - * @enable: on/off - */ -int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable); - /** * sun6i_csi_update_config() - update the csi register settings * @csi: pointer to the csi diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index ab6e298864ed..05eb9aae2975 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -6,6 +6,7 @@ */ #include +#include #include #include @@ -141,6 +142,9 @@ static void sun6i_csi_capture_enable(struct sun6i_csi_device *csi_dev) { struct regmap *regmap = csi_dev->regmap; + regmap_update_bits(regmap, SUN6I_CSI_EN_REG, SUN6I_CSI_EN_CSI_EN, + SUN6I_CSI_EN_CSI_EN); + regmap_update_bits(regmap, SUN6I_CSI_CAP_REG, SUN6I_CSI_CAP_VCAP_ON, SUN6I_CSI_CAP_VCAP_ON); } @@ -150,6 +154,7 @@ static void sun6i_csi_capture_disable(struct sun6i_csi_device *csi_dev) struct regmap *regmap = csi_dev->regmap; regmap_update_bits(regmap, SUN6I_CSI_CAP_REG, SUN6I_CSI_CAP_VCAP_ON, 0); + regmap_update_bits(regmap, SUN6I_CSI_EN_REG, SUN6I_CSI_EN_CSI_EN, 0); } static void @@ -382,6 +387,7 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, struct sun6i_csi_capture *capture = &csi_dev->capture; struct sun6i_csi_capture_state *state = &capture->state; struct video_device *video_dev = &capture->video_dev; + struct device *dev = csi_dev->dev; struct v4l2_subdev *subdev; int ret; @@ -402,6 +408,12 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, goto error_media_pipeline; } + /* PM */ + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + goto error_media_pipeline; + /* Clear */ sun6i_csi_capture_irq_clear(csi_dev); @@ -429,6 +441,8 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, sun6i_csi_capture_disable(csi_dev); sun6i_csi_capture_irq_disable(csi_dev); + pm_runtime_put(dev); + error_media_pipeline: media_pipeline_stop(&video_dev->entity); @@ -442,6 +456,7 @@ static void sun6i_csi_capture_stop_streaming(struct vb2_queue *queue) { struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); struct sun6i_csi_capture *capture = &csi_dev->capture; + struct device *dev = csi_dev->dev; struct v4l2_subdev *subdev; subdev = sun6i_csi_capture_remote_subdev(capture, NULL); @@ -451,6 +466,8 @@ static void sun6i_csi_capture_stop_streaming(struct vb2_queue *queue) sun6i_csi_capture_disable(csi_dev); sun6i_csi_capture_irq_disable(csi_dev); + pm_runtime_put(dev); + media_pipeline_stop(&capture->video_dev.entity); sun6i_csi_capture_state_cleanup(csi_dev, true); @@ -635,27 +652,20 @@ static int sun6i_csi_capture_open(struct file *file) if (mutex_lock_interruptible(&capture->lock)) return -ERESTARTSYS; - ret = v4l2_fh_open(file); + ret = v4l2_pipeline_pm_get(&capture->video_dev.entity); if (ret < 0) goto error_lock; - ret = v4l2_pipeline_pm_get(&capture->video_dev.entity); + ret = v4l2_fh_open(file); if (ret < 0) - goto error_v4l2_fh; - - /* Power on at first open. */ - if (v4l2_fh_is_singular_file(file)) { - ret = sun6i_csi_set_power(csi_dev, true); - if (ret < 0) - goto error_v4l2_fh; - } + goto error_pipeline; mutex_unlock(&capture->lock); return 0; -error_v4l2_fh: - v4l2_fh_release(file); +error_pipeline: + v4l2_pipeline_pm_put(&capture->video_dev.entity); error_lock: mutex_unlock(&capture->lock); @@ -667,19 +677,12 @@ static int sun6i_csi_capture_close(struct file *file) { struct sun6i_csi_device *csi_dev = video_drvdata(file); struct sun6i_csi_capture *capture = &csi_dev->capture; - bool last_close; mutex_lock(&capture->lock); - last_close = v4l2_fh_is_singular_file(file); - _vb2_fop_release(file, NULL); v4l2_pipeline_pm_put(&capture->video_dev.entity); - /* Power off at last close. */ - if (last_close) - sun6i_csi_set_power(csi_dev, false); - mutex_unlock(&capture->lock); return 0; From patchwork Fri Mar 11 14:35:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778126 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3AEE4C433EF for ; Fri, 11 Mar 2022 14:36:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349595AbiCKOho (ORCPT ); Fri, 11 Mar 2022 09:37:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58904 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349519AbiCKOhf (ORCPT ); Fri, 11 Mar 2022 09:37:35 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4737F1C944E; Fri, 11 Mar 2022 06:36:27 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 14E2A240011; Fri, 11 Mar 2022 14:36:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009386; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=50tQJhzgI3JfRW3v0eERsdj58dWyIdZrxa9ns+xrtZ0=; b=NUpzyHt8ZnMCgKL+s8w1pYPCMF/ufCM8Gm4YozF8SRfzqtZ5NhjTl6bao1sHVl/lL3SPEz XzmbN4Y/tD8FGniuJZ+yjo8g6OHFwayrBPiItGLZQSDn3pYQJrzl75TdY6EaJKC1ji+fhV 5Y1qzhsUwZ2xaC/R0neoEs33qpXWcOGPM/lU19tJ5M5xFeUs3E+W5JLTxR7DO9NAk8XIP8 g7KmT60vZSeTbwzrsVS+kIJk2toIZZ0BL4cDlcEcOk+ageFVI4F+E0fkLI6B0CCsJZYUt3 2bhHLsoBsDJ7y/4DIjwTSfOR18CjTU9gNtoHvxFLZiq5sXs2i7y7YCrdnUk27g== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 24/46] media: sun6i-csi: Move register configuration to capture Date: Fri, 11 Mar 2022 15:35:10 +0100 Message-Id: <20220311143532.265091-25-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Continue moving things over to capture in tidy helpers. Also take the occasion to remove the config struct, which is unwelcome redundancy and use the capture helpers instead. The code is only adapted to reflect the removal of the config structure. No functional change intended. Signed-off-by: Paul Kocialkowski --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 363 ----------------- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 25 -- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 364 +++++++++++++++++- 3 files changed, 356 insertions(+), 396 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index aa7350170eef..b0aa5cfdd681 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -148,369 +148,6 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev, return false; } -static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_device *csi_dev, - u32 mbus_code, u32 pixformat) -{ - /* non-YUV */ - if ((mbus_code & 0xF000) != 0x2000) - return CSI_INPUT_FORMAT_RAW; - - switch (pixformat) { - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_VYUY: - return CSI_INPUT_FORMAT_RAW; - default: - break; - } - - /* not support YUV420 input format yet */ - dev_dbg(csi_dev->dev, "Select YUV422 as default input format of CSI.\n"); - return CSI_INPUT_FORMAT_YUV422; -} - -static enum csi_output_fmt -get_csi_output_format(struct sun6i_csi_device *csi_dev, u32 pixformat, - u32 field) -{ - bool buf_interlaced = false; - - if (field == V4L2_FIELD_INTERLACED - || field == V4L2_FIELD_INTERLACED_TB - || field == V4L2_FIELD_INTERLACED_BT) - buf_interlaced = true; - - switch (pixformat) { - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8; - case V4L2_PIX_FMT_SBGGR10: - case V4L2_PIX_FMT_SGBRG10: - case V4L2_PIX_FMT_SGRBG10: - case V4L2_PIX_FMT_SRGGB10: - return buf_interlaced ? CSI_FRAME_RAW_10 : CSI_FIELD_RAW_10; - case V4L2_PIX_FMT_SBGGR12: - case V4L2_PIX_FMT_SGBRG12: - case V4L2_PIX_FMT_SGRBG12: - case V4L2_PIX_FMT_SRGGB12: - return buf_interlaced ? CSI_FRAME_RAW_12 : CSI_FIELD_RAW_12; - - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_VYUY: - return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8; - - case V4L2_PIX_FMT_NV12_16L16: - return buf_interlaced ? CSI_FRAME_MB_YUV420 : - CSI_FIELD_MB_YUV420; - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - return buf_interlaced ? CSI_FRAME_UV_CB_YUV420 : - CSI_FIELD_UV_CB_YUV420; - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - return buf_interlaced ? CSI_FRAME_PLANAR_YUV420 : - CSI_FIELD_PLANAR_YUV420; - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - return buf_interlaced ? CSI_FRAME_UV_CB_YUV422 : - CSI_FIELD_UV_CB_YUV422; - case V4L2_PIX_FMT_YUV422P: - return buf_interlaced ? CSI_FRAME_PLANAR_YUV422 : - CSI_FIELD_PLANAR_YUV422; - - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB565X: - return buf_interlaced ? CSI_FRAME_RGB565 : CSI_FIELD_RGB565; - - case V4L2_PIX_FMT_JPEG: - return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8; - - default: - dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x\n", pixformat); - break; - } - - return CSI_FIELD_RAW_8; -} - -static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_device *csi_dev, - u32 mbus_code, u32 pixformat) -{ - /* Input sequence does not apply to non-YUV formats */ - if ((mbus_code & 0xF000) != 0x2000) - return 0; - - switch (pixformat) { - case V4L2_PIX_FMT_NV12_16L16: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YUV422P: - switch (mbus_code) { - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_UYVY8_1X16: - return CSI_INPUT_SEQ_UYVY; - case MEDIA_BUS_FMT_VYUY8_2X8: - case MEDIA_BUS_FMT_VYUY8_1X16: - return CSI_INPUT_SEQ_VYUY; - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_YUYV8_1X16: - return CSI_INPUT_SEQ_YUYV; - case MEDIA_BUS_FMT_YVYU8_1X16: - case MEDIA_BUS_FMT_YVYU8_2X8: - return CSI_INPUT_SEQ_YVYU; - default: - dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n", - mbus_code); - break; - } - break; - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV61: - case V4L2_PIX_FMT_YVU420: - switch (mbus_code) { - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_UYVY8_1X16: - return CSI_INPUT_SEQ_VYUY; - case MEDIA_BUS_FMT_VYUY8_2X8: - case MEDIA_BUS_FMT_VYUY8_1X16: - return CSI_INPUT_SEQ_UYVY; - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_YUYV8_1X16: - return CSI_INPUT_SEQ_YVYU; - case MEDIA_BUS_FMT_YVYU8_1X16: - case MEDIA_BUS_FMT_YVYU8_2X8: - return CSI_INPUT_SEQ_YUYV; - default: - dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n", - mbus_code); - break; - } - break; - - case V4L2_PIX_FMT_YUYV: - return CSI_INPUT_SEQ_YUYV; - - default: - dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x, defaulting to YUYV\n", - pixformat); - break; - } - - return CSI_INPUT_SEQ_YUYV; -} - -static void sun6i_csi_setup_bus(struct sun6i_csi_device *csi_dev) -{ - struct v4l2_fwnode_endpoint *endpoint = - &csi_dev->bridge.source->endpoint; - struct sun6i_csi_config *config = &csi_dev->config; - unsigned char bus_width; - u32 flags; - u32 cfg = 0; - bool input_interlaced = false; - - if (config->field == V4L2_FIELD_INTERLACED - || config->field == V4L2_FIELD_INTERLACED_TB - || config->field == V4L2_FIELD_INTERLACED_BT) - input_interlaced = true; - - bus_width = endpoint->bus.parallel.bus_width; - - if (input_interlaced) - cfg |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED | - SUN6I_CSI_IF_CFG_FIELD_DT_PCLK_SHIFT(1) | - SUN6I_CSI_IF_CFG_FIELD_DT_FIELD_VSYNC; - else - cfg |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE; - - switch (endpoint->bus_type) { - case V4L2_MBUS_PARALLEL: - cfg |= SUN6I_CSI_IF_CFG_IF_CSI; - - flags = endpoint->bus.parallel.flags; - - if (bus_width == 16) - cfg |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_COMBINED; - else - cfg |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_RAW; - - if (flags & V4L2_MBUS_FIELD_EVEN_LOW) - cfg |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE; - else - cfg |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE; - - if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - cfg |= SUN6I_CSI_IF_CFG_VREF_POL_NEGATIVE; - else - cfg |= SUN6I_CSI_IF_CFG_VREF_POL_POSITIVE; - - if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - cfg |= SUN6I_CSI_IF_CFG_HREF_POL_NEGATIVE; - else - cfg |= SUN6I_CSI_IF_CFG_HREF_POL_POSITIVE; - - if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) - cfg |= SUN6I_CSI_IF_CFG_CLK_POL_RISING; - else - cfg |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING; - break; - case V4L2_MBUS_BT656: - cfg |= SUN6I_CSI_IF_CFG_IF_CSI; - - flags = endpoint->bus.parallel.flags; - - if (bus_width == 16) - cfg |= SUN6I_CSI_IF_CFG_IF_CSI_BT1120; - else - cfg |= SUN6I_CSI_IF_CFG_IF_CSI_BT656; - - if (flags & V4L2_MBUS_FIELD_EVEN_LOW) - cfg |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE; - else - cfg |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE; - - if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) - cfg |= SUN6I_CSI_IF_CFG_CLK_POL_RISING; - else - cfg |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING; - break; - default: - dev_warn(csi_dev->dev, "Unsupported bus type: %d\n", - endpoint->bus_type); - break; - } - - switch (bus_width) { - case 8: - cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_8; - break; - case 10: - cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_10; - break; - case 12: - cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_12; - break; - case 16: /* No need to configure DATA_WIDTH for 16bit */ - break; - default: - dev_warn(csi_dev->dev, "Unsupported bus width: %u\n", bus_width); - break; - } - - regmap_write(csi_dev->regmap, SUN6I_CSI_IF_CFG_REG, cfg); -} - -static void sun6i_csi_set_format(struct sun6i_csi_device *csi_dev) -{ - struct sun6i_csi_config *config = &csi_dev->config; - u32 cfg = 0; - u32 val; - - val = get_csi_input_format(csi_dev, config->code, - config->pixelformat); - cfg |= SUN6I_CSI_CH_CFG_INPUT_FMT(val); - - val = get_csi_output_format(csi_dev, config->pixelformat, - config->field); - cfg |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(val); - - val = get_csi_input_seq(csi_dev, config->code, - config->pixelformat); - cfg |= SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(val); - - if (config->field == V4L2_FIELD_TOP) - cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD0; - else if (config->field == V4L2_FIELD_BOTTOM) - cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD1; - else - cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_EITHER; - - regmap_write(csi_dev->regmap, SUN6I_CSI_CH_CFG_REG, cfg); -} - -static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev) -{ - struct sun6i_csi_config *config = &csi_dev->config; - u32 bytesperline_y; - u32 bytesperline_c; - u32 width = config->width; - u32 height = config->height; - u32 hor_len = width; - - switch (config->pixelformat) { - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_VYUY: - dev_dbg(csi_dev->dev, - "Horizontal length should be 2 times of width for packed YUV formats!\n"); - hor_len = width * 2; - break; - default: - break; - } - - regmap_write(csi_dev->regmap, SUN6I_CSI_CH_HSIZE_REG, - SUN6I_CSI_CH_HSIZE_LEN(hor_len) | - SUN6I_CSI_CH_HSIZE_START(0)); - regmap_write(csi_dev->regmap, SUN6I_CSI_CH_VSIZE_REG, - SUN6I_CSI_CH_VSIZE_LEN(height) | - SUN6I_CSI_CH_VSIZE_START(0)); - - switch (config->pixelformat) { - case V4L2_PIX_FMT_NV12_16L16: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - bytesperline_y = width; - bytesperline_c = width; - break; - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - bytesperline_y = width; - bytesperline_c = width / 2; - break; - case V4L2_PIX_FMT_YUV422P: - bytesperline_y = width; - bytesperline_c = width / 2; - break; - default: /* raw */ - dev_dbg(csi_dev->dev, - "Calculating pixelformat(0x%x)'s bytesperline as a packed format\n", - config->pixelformat); - bytesperline_y = (sun6i_csi_get_bpp(config->pixelformat) * - config->width) / 8; - bytesperline_c = 0; - break; - } - - regmap_write(csi_dev->regmap, SUN6I_CSI_CH_BUF_LEN_REG, - SUN6I_CSI_CH_BUF_LEN_CHROMA_LINE(bytesperline_c) | - SUN6I_CSI_CH_BUF_LEN_LUMA_LINE(bytesperline_y)); -} - -int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev, - struct sun6i_csi_config *config) -{ - if (!config) - return -EINVAL; - - memcpy(&csi_dev->config, config, sizeof(csi_dev->config)); - - sun6i_csi_setup_bus(csi_dev); - sun6i_csi_set_format(csi_dev); - sun6i_csi_set_window(csi_dev); - - return 0; -} - /* Media */ static const struct media_device_ops sun6i_csi_media_ops = { diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 4a40a65cf1a2..8a9586e02f73 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -28,22 +28,6 @@ struct sun6i_csi_buffer { struct list_head list; }; -/** - * struct sun6i_csi_config - configs for sun6i csi - * @pixelformat: v4l2 pixel format (V4L2_PIX_FMT_*) - * @code: media bus format code (MEDIA_BUS_FMT_*) - * @field: used interlacing type (enum v4l2_field) - * @width: frame width - * @height: frame height - */ -struct sun6i_csi_config { - u32 pixelformat; - u32 code; - u32 field; - u32 width; - u32 height; -}; - struct sun6i_csi_v4l2 { struct v4l2_device v4l2_dev; struct v4l2_ctrl_handler ctrl_handler; @@ -53,7 +37,6 @@ struct sun6i_csi_v4l2 { struct sun6i_csi_device { struct device *dev; - struct sun6i_csi_config config; struct sun6i_csi_v4l2 v4l2; struct sun6i_csi_bridge bridge; struct sun6i_csi_capture capture; @@ -78,14 +61,6 @@ struct sun6i_csi_variant { bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev, u32 pixformat, u32 mbus_code); -/** - * sun6i_csi_update_config() - update the csi register settings - * @csi: pointer to the csi - * @config: see struct sun6i_csi_config - */ -int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev, - struct sun6i_csi_config *config); - /* get bpp form v4l2 pixformat */ static inline int sun6i_csi_get_bpp(unsigned int pixformat) { diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 05eb9aae2975..23b13b26b580 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -198,18 +198,366 @@ sun6i_csi_capture_buffer_configure(struct sun6i_csi_device *csi_dev, } } -static void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev) +static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_device *csi_dev, + u32 mbus_code, u32 pixformat) +{ + /* non-YUV */ + if ((mbus_code & 0xF000) != 0x2000) + return CSI_INPUT_FORMAT_RAW; + + switch (pixformat) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + return CSI_INPUT_FORMAT_RAW; + default: + break; + } + + /* not support YUV420 input format yet */ + dev_dbg(csi_dev->dev, "Select YUV422 as default input format of CSI.\n"); + return CSI_INPUT_FORMAT_YUV422; +} + +static enum csi_output_fmt +get_csi_output_format(struct sun6i_csi_device *csi_dev, u32 pixformat, + u32 field) +{ + bool buf_interlaced = false; + + if (field == V4L2_FIELD_INTERLACED + || field == V4L2_FIELD_INTERLACED_TB + || field == V4L2_FIELD_INTERLACED_BT) + buf_interlaced = true; + + switch (pixformat) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + return buf_interlaced ? CSI_FRAME_RAW_10 : CSI_FIELD_RAW_10; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + return buf_interlaced ? CSI_FRAME_RAW_12 : CSI_FIELD_RAW_12; + + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8; + + case V4L2_PIX_FMT_NV12_16L16: + return buf_interlaced ? CSI_FRAME_MB_YUV420 : + CSI_FIELD_MB_YUV420; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + return buf_interlaced ? CSI_FRAME_UV_CB_YUV420 : + CSI_FIELD_UV_CB_YUV420; + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + return buf_interlaced ? CSI_FRAME_PLANAR_YUV420 : + CSI_FIELD_PLANAR_YUV420; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + return buf_interlaced ? CSI_FRAME_UV_CB_YUV422 : + CSI_FIELD_UV_CB_YUV422; + case V4L2_PIX_FMT_YUV422P: + return buf_interlaced ? CSI_FRAME_PLANAR_YUV422 : + CSI_FIELD_PLANAR_YUV422; + + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + return buf_interlaced ? CSI_FRAME_RGB565 : CSI_FIELD_RGB565; + + case V4L2_PIX_FMT_JPEG: + return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8; + + default: + dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x\n", pixformat); + break; + } + + return CSI_FIELD_RAW_8; +} + +static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_device *csi_dev, + u32 mbus_code, u32 pixformat) +{ + /* Input sequence does not apply to non-YUV formats */ + if ((mbus_code & 0xF000) != 0x2000) + return 0; + + switch (pixformat) { + case V4L2_PIX_FMT_NV12_16L16: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YUV422P: + switch (mbus_code) { + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: + return CSI_INPUT_SEQ_UYVY; + case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: + return CSI_INPUT_SEQ_VYUY; + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: + return CSI_INPUT_SEQ_YUYV; + case MEDIA_BUS_FMT_YVYU8_1X16: + case MEDIA_BUS_FMT_YVYU8_2X8: + return CSI_INPUT_SEQ_YVYU; + default: + dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n", + mbus_code); + break; + } + break; + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_YVU420: + switch (mbus_code) { + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_UYVY8_1X16: + return CSI_INPUT_SEQ_VYUY; + case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_VYUY8_1X16: + return CSI_INPUT_SEQ_UYVY; + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_1X16: + return CSI_INPUT_SEQ_YVYU; + case MEDIA_BUS_FMT_YVYU8_1X16: + case MEDIA_BUS_FMT_YVYU8_2X8: + return CSI_INPUT_SEQ_YUYV; + default: + dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n", + mbus_code); + break; + } + break; + + case V4L2_PIX_FMT_YUYV: + return CSI_INPUT_SEQ_YUYV; + + default: + dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x, defaulting to YUYV\n", + pixformat); + break; + } + + return CSI_INPUT_SEQ_YUYV; +} + +static void +sun6i_csi_capture_configure_interface(struct sun6i_csi_device *csi_dev) +{ + struct v4l2_fwnode_endpoint *endpoint = + &csi_dev->bridge.source->endpoint; + u32 pixelformat, field; + unsigned char bus_width; + u32 flags; + u32 cfg = 0; + bool input_interlaced = false; + + sun6i_csi_capture_format(csi_dev, &pixelformat, &field); + + if (field == V4L2_FIELD_INTERLACED || + field == V4L2_FIELD_INTERLACED_TB || + field == V4L2_FIELD_INTERLACED_BT) + input_interlaced = true; + + bus_width = endpoint->bus.parallel.bus_width; + + if (input_interlaced) + cfg |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED | + SUN6I_CSI_IF_CFG_FIELD_DT_PCLK_SHIFT(1) | + SUN6I_CSI_IF_CFG_FIELD_DT_FIELD_VSYNC; + else + cfg |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE; + + switch (endpoint->bus_type) { + case V4L2_MBUS_PARALLEL: + cfg |= SUN6I_CSI_IF_CFG_IF_CSI; + + flags = endpoint->bus.parallel.flags; + + if (bus_width == 16) + cfg |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_COMBINED; + else + cfg |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_RAW; + + if (flags & V4L2_MBUS_FIELD_EVEN_LOW) + cfg |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE; + else + cfg |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE; + + if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + cfg |= SUN6I_CSI_IF_CFG_VREF_POL_NEGATIVE; + else + cfg |= SUN6I_CSI_IF_CFG_VREF_POL_POSITIVE; + + if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + cfg |= SUN6I_CSI_IF_CFG_HREF_POL_NEGATIVE; + else + cfg |= SUN6I_CSI_IF_CFG_HREF_POL_POSITIVE; + + if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) + cfg |= SUN6I_CSI_IF_CFG_CLK_POL_RISING; + else + cfg |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING; + break; + case V4L2_MBUS_BT656: + cfg |= SUN6I_CSI_IF_CFG_IF_CSI; + + flags = endpoint->bus.parallel.flags; + + if (bus_width == 16) + cfg |= SUN6I_CSI_IF_CFG_IF_CSI_BT1120; + else + cfg |= SUN6I_CSI_IF_CFG_IF_CSI_BT656; + + if (flags & V4L2_MBUS_FIELD_EVEN_LOW) + cfg |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE; + else + cfg |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE; + + if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) + cfg |= SUN6I_CSI_IF_CFG_CLK_POL_RISING; + else + cfg |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING; + break; + default: + dev_warn(csi_dev->dev, "Unsupported bus type: %d\n", + endpoint->bus_type); + break; + } + + switch (bus_width) { + case 8: + cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_8; + break; + case 10: + cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_10; + break; + case 12: + cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_12; + break; + case 16: /* No need to configure DATA_WIDTH for 16bit */ + break; + default: + dev_warn(csi_dev->dev, "Unsupported bus width: %u\n", bus_width); + break; + } + + regmap_write(csi_dev->regmap, SUN6I_CSI_IF_CFG_REG, cfg); +} + +static void sun6i_csi_capture_configure_format(struct sun6i_csi_device *csi_dev) { struct sun6i_csi_capture *capture = &csi_dev->capture; - struct sun6i_csi_config config = { 0 }; + u32 pixelformat, field; + u32 cfg = 0; + u32 val; + + sun6i_csi_capture_format(csi_dev, &pixelformat, &field); + + val = get_csi_input_format(csi_dev, capture->mbus_code, pixelformat); + cfg |= SUN6I_CSI_CH_CFG_INPUT_FMT(val); + + val = get_csi_output_format(csi_dev, pixelformat, field); + cfg |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(val); + + val = get_csi_input_seq(csi_dev, capture->mbus_code, pixelformat); + cfg |= SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(val); + + if (field == V4L2_FIELD_TOP) + cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD0; + else if (field == V4L2_FIELD_BOTTOM) + cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD1; + else + cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_EITHER; + + regmap_write(csi_dev->regmap, SUN6I_CSI_CH_CFG_REG, cfg); +} - config.pixelformat = capture->format.fmt.pix.pixelformat; - config.code = capture->mbus_code; - config.field = capture->format.fmt.pix.field; - config.width = capture->format.fmt.pix.width; - config.height = capture->format.fmt.pix.height; +static void sun6i_csi_capture_configure_window(struct sun6i_csi_device *csi_dev) +{ + u32 pixelformat, field; + u32 width, height; + u32 bytesperline_y; + u32 bytesperline_c; + u32 hor_len; + + sun6i_csi_capture_dimensions(csi_dev, &width, &height); + sun6i_csi_capture_format(csi_dev, &pixelformat, &field); + + hor_len = width; + + switch (pixelformat) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + dev_dbg(csi_dev->dev, + "Horizontal length should be 2 times of width for packed YUV formats!\n"); + hor_len = width * 2; + break; + default: + break; + } + + regmap_write(csi_dev->regmap, SUN6I_CSI_CH_HSIZE_REG, + SUN6I_CSI_CH_HSIZE_LEN(hor_len) | + SUN6I_CSI_CH_HSIZE_START(0)); + regmap_write(csi_dev->regmap, SUN6I_CSI_CH_VSIZE_REG, + SUN6I_CSI_CH_VSIZE_LEN(height) | + SUN6I_CSI_CH_VSIZE_START(0)); + + switch (pixelformat) { + case V4L2_PIX_FMT_NV12_16L16: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + bytesperline_y = width; + bytesperline_c = width; + break; + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + bytesperline_y = width; + bytesperline_c = width / 2; + break; + case V4L2_PIX_FMT_YUV422P: + bytesperline_y = width; + bytesperline_c = width / 2; + break; + default: /* raw */ + dev_dbg(csi_dev->dev, + "Calculating pixelformat(0x%x)'s bytesperline as a packed format\n", + pixelformat); + bytesperline_y = (sun6i_csi_get_bpp(pixelformat) * + width) / 8; + bytesperline_c = 0; + break; + } + + regmap_write(csi_dev->regmap, SUN6I_CSI_CH_BUF_LEN_REG, + SUN6I_CSI_CH_BUF_LEN_CHROMA_LINE(bytesperline_c) | + SUN6I_CSI_CH_BUF_LEN_LUMA_LINE(bytesperline_y)); +} - sun6i_csi_update_config(csi_dev, &config); +static void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev) +{ + sun6i_csi_capture_configure_interface(csi_dev); + sun6i_csi_capture_configure_format(csi_dev); + sun6i_csi_capture_configure_window(csi_dev); } /* State */ From patchwork Fri Mar 11 14:35:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778128 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 281BEC4321E for ; Fri, 11 Mar 2022 14:36:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349528AbiCKOhy (ORCPT ); Fri, 11 Mar 2022 09:37:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59596 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347893AbiCKOhh (ORCPT ); Fri, 11 Mar 2022 09:37:37 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 877891C8DAF; Fri, 11 Mar 2022 06:36:29 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id CB64F240018; Fri, 11 Mar 2022 14:36:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009388; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=dQus7XQbf+fPVF49Vs3xuZQt/goLCAbN0lflmcEfzP4=; b=bvZPTuX4+xw6VMy+lfNLNtI/DflUxLisl4Zkx127lYoYqOny+RP+V9HGrEQK0L57618Qr8 zAANHLWi4sLD5EQZ+4RiT/puhM/6JW2eSsOLkvhn3kt9HupdvRUm+ogHH1iUdBjuDx05Tf 5A/TjSZcnKm9fIpHmMRt57RPrr1fzS7BXVrDfu03p38PT4sAQ4q09H+8ZMedaZ26kJ0jKs 0/H3qbA6E3rLagxKUnvCTXgmM3o0Qxp4cRRIqBKxYsXlUC375+n7++383SngPG2f8EGRA4 srvHUrFp6Zu9XePD1BE7dL5J//L+qY/GGgZK4D6o2RN/AsQ0zOVSzrAfM4B/GA== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 25/46] media: sun6i-csi: Rework capture format management with helper Date: Fri, 11 Mar 2022 15:35:11 +0100 Message-Id: <20220311143532.265091-26-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Remove the need for local copies of the v4l2 format and add a common helper to prepare a format compatible with the driver, using the relevant v4l2 helper. Also cleanup the size bound defines while at it. Signed-off-by: Paul Kocialkowski --- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 109 +++++++++--------- .../sunxi/sun6i-csi/sun6i_csi_capture.h | 5 + 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 23b13b26b580..9c8b33c7e59c 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -20,12 +20,6 @@ #include "sun6i_csi_capture.h" #include "sun6i_csi_reg.h" -/* This is got from BSP sources. */ -#define MIN_WIDTH (32) -#define MIN_HEIGHT (32) -#define MAX_WIDTH (4800) -#define MAX_HEIGHT (4800) - /* Helpers */ void sun6i_csi_capture_dimensions(struct sun6i_csi_device *csi_dev, @@ -833,6 +827,46 @@ static const struct vb2_ops sun6i_csi_capture_queue_ops = { /* V4L2 Device */ +static void sun6i_csi_capture_format_prepare(struct v4l2_format *format) +{ + struct v4l2_pix_format *pix_format = &format->fmt.pix; + unsigned int width, height; + + v4l_bound_align_image(&pix_format->width, SUN6I_CSI_CAPTURE_WIDTH_MIN, + SUN6I_CSI_CAPTURE_WIDTH_MAX, 1, + &pix_format->height, SUN6I_CSI_CAPTURE_HEIGHT_MIN, + SUN6I_CSI_CAPTURE_HEIGHT_MAX, 1, 0); + + if (!sun6i_csi_capture_format_check(pix_format->pixelformat)) + pix_format->pixelformat = sun6i_csi_capture_formats[0]; + + width = pix_format->width; + height = pix_format->height; + + switch (pix_format->pixelformat) { + case V4L2_PIX_FMT_NV12_16L16: + pix_format->bytesperline = width * 12 / 8; + pix_format->sizeimage = pix_format->bytesperline * height; + break; + case V4L2_PIX_FMT_JPEG: + pix_format->bytesperline = width; + pix_format->sizeimage = pix_format->bytesperline * height; + break; + default: + v4l2_fill_pixfmt(pix_format, pix_format->pixelformat, + width, height); + break; + } + + if (pix_format->field == V4L2_FIELD_ANY) + pix_format->field = V4L2_FIELD_NONE; + + pix_format->colorspace = V4L2_COLORSPACE_RAW; + pix_format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + pix_format->quantization = V4L2_QUANTIZATION_DEFAULT; + pix_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; +} + static int sun6i_csi_capture_querycap(struct file *file, void *private, struct v4l2_capability *capability) { @@ -864,50 +898,8 @@ static int sun6i_csi_capture_g_fmt(struct file *file, void *private, struct v4l2_format *format) { struct sun6i_csi_device *csi_dev = video_drvdata(file); - struct sun6i_csi_capture *capture = &csi_dev->capture; - *format = capture->format; - - return 0; -} - -static int sun6i_csi_capture_format_try(struct sun6i_csi_capture *capture, - struct v4l2_format *format) -{ - struct v4l2_pix_format *pix_format = &format->fmt.pix; - int bpp; - - if (!sun6i_csi_capture_format_check(pix_format->pixelformat)) - pix_format->pixelformat = sun6i_csi_capture_formats[0]; - - v4l_bound_align_image(&pix_format->width, MIN_WIDTH, MAX_WIDTH, 1, - &pix_format->height, MIN_HEIGHT, MAX_WIDTH, 1, 1); - - bpp = sun6i_csi_get_bpp(pix_format->pixelformat); - pix_format->bytesperline = (pix_format->width * bpp) >> 3; - pix_format->sizeimage = pix_format->bytesperline * pix_format->height; - - if (pix_format->field == V4L2_FIELD_ANY) - pix_format->field = V4L2_FIELD_NONE; - - pix_format->colorspace = V4L2_COLORSPACE_RAW; - pix_format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - pix_format->quantization = V4L2_QUANTIZATION_DEFAULT; - pix_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; - - return 0; -} - -static int sun6i_csi_capture_format_set(struct sun6i_csi_capture *capture, - struct v4l2_format *format) -{ - int ret; - - ret = sun6i_csi_capture_format_try(capture, format); - if (ret) - return ret; - - capture->format = *format; + *format = csi_dev->capture.format; return 0; } @@ -921,16 +913,19 @@ static int sun6i_csi_capture_s_fmt(struct file *file, void *private, if (vb2_is_busy(&capture->queue)) return -EBUSY; - return sun6i_csi_capture_format_set(capture, format); + sun6i_csi_capture_format_prepare(format); + + csi_dev->capture.format = *format; + + return 0; } static int sun6i_csi_capture_try_fmt(struct file *file, void *private, struct v4l2_format *format) { - struct sun6i_csi_device *csi_dev = video_drvdata(file); - struct sun6i_csi_capture *capture = &csi_dev->capture; + sun6i_csi_capture_format_prepare(format); - return sun6i_csi_capture_format_try(capture, format); + return 0; } static int sun6i_csi_capture_enum_input(struct file *file, void *private, @@ -1125,8 +1120,8 @@ int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev) struct video_device *video_dev = &capture->video_dev; struct vb2_queue *queue = &capture->queue; struct media_pad *pad = &capture->pad; - struct v4l2_format format = { 0 }; - struct v4l2_pix_format *pix_format = &format.fmt.pix; + struct v4l2_format *format = &csi_dev->capture.format; + struct v4l2_pix_format *pix_format = &format->fmt.pix; int ret; /* State */ @@ -1169,13 +1164,13 @@ int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev) /* V4L2 Format */ - format.type = queue->type; + format->type = queue->type; pix_format->pixelformat = sun6i_csi_capture_formats[0]; pix_format->width = 1280; pix_format->height = 720; pix_format->field = V4L2_FIELD_NONE; - sun6i_csi_capture_format_set(capture, &format); + sun6i_csi_capture_format_prepare(format); /* Video Device */ diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h index 935f35b7049a..02bdf45f7ca5 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h @@ -11,6 +11,11 @@ #include #include +#define SUN6I_CSI_CAPTURE_WIDTH_MIN 32 +#define SUN6I_CSI_CAPTURE_WIDTH_MAX 4800 +#define SUN6I_CSI_CAPTURE_HEIGHT_MIN 32 +#define SUN6I_CSI_CAPTURE_HEIGHT_MAX 4800 + struct sun6i_csi_device; #undef current From patchwork Fri Mar 11 14:35:12 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778154 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C429DC433FE for ; Fri, 11 Mar 2022 14:38:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345892AbiCKOjr (ORCPT ); Fri, 11 Mar 2022 09:39:47 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59474 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349574AbiCKOhj (ORCPT ); Fri, 11 Mar 2022 09:37:39 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 34A801C9455; Fri, 11 Mar 2022 06:36:30 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 50B90240004; Fri, 11 Mar 2022 14:36:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009389; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=iggvo2rKOQxtmuPw2qJyHa5S/fk0RafXxscwtfDj1dg=; b=l9t27ymgioqxk7VMuWg/PvC3tPc7/UErsoxRubSz31jmRdbEC0qRkTI0l+7Yonz1Ba8MUz VVKgEiwiGzKKZzK96DGmG9o/JFR2xhwQcjFYA677mnScynZ9MlRl77npkKBGQta/uouBpT eRNdAxPFeeMv2LSX5GV2LPAcRfZCtJT+UwVcJ7BV95fecJ2JJS2x/XtRVoydAW81Zg7UyL p/Rx39pi2Vwga2MUx4zewJD8Bas7j1ttgYhiiE3mPJI1JcNm/6BEorzAq3uAeFsv6pKWE2 9sxevk6fr/NG64ZB2LF+jzsalYlpbdWdZmxV40yRJYCfuMmkD1vaaVh+Qxm0ig== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 26/46] media: sun6i-csi: Remove custom format helper and rework configure Date: Fri, 11 Mar 2022 15:35:12 +0100 Message-Id: <20220311143532.265091-27-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Remove the custom sun6i_csi_get_bpp helper in favor of common v4l2 infrastructure and rework the related window configuration code. Signed-off-by: Paul Kocialkowski --- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 49 ------------- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 70 +++++++++---------- 2 files changed, 35 insertions(+), 84 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 8a9586e02f73..21932aae3636 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -61,53 +61,4 @@ struct sun6i_csi_variant { bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev, u32 pixformat, u32 mbus_code); -/* get bpp form v4l2 pixformat */ -static inline int sun6i_csi_get_bpp(unsigned int pixformat) -{ - switch (pixformat) { - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - case V4L2_PIX_FMT_JPEG: - return 8; - case V4L2_PIX_FMT_SBGGR10: - case V4L2_PIX_FMT_SGBRG10: - case V4L2_PIX_FMT_SGRBG10: - case V4L2_PIX_FMT_SRGGB10: - return 10; - case V4L2_PIX_FMT_SBGGR12: - case V4L2_PIX_FMT_SGBRG12: - case V4L2_PIX_FMT_SGRBG12: - case V4L2_PIX_FMT_SRGGB12: - case V4L2_PIX_FMT_NV12_16L16: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - return 12; - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_VYUY: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - case V4L2_PIX_FMT_YUV422P: - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB565X: - return 16; - case V4L2_PIX_FMT_RGB24: - case V4L2_PIX_FMT_BGR24: - return 24; - case V4L2_PIX_FMT_RGB32: - case V4L2_PIX_FMT_BGR32: - return 32; - default: - WARN(1, "Unsupported pixformat: 0x%x\n", pixformat); - break; - } - - return 0; -} - #endif /* __SUN6I_CSI_H__ */ diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 9c8b33c7e59c..f977b89dcea2 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -483,68 +483,68 @@ static void sun6i_csi_capture_configure_format(struct sun6i_csi_device *csi_dev) static void sun6i_csi_capture_configure_window(struct sun6i_csi_device *csi_dev) { + struct regmap *regmap = csi_dev->regmap; + const struct v4l2_format_info *info; + u32 hsize_len, vsize_len; + u32 luma_line, chroma_line = 0; u32 pixelformat, field; u32 width, height; - u32 bytesperline_y; - u32 bytesperline_c; - u32 hor_len; sun6i_csi_capture_dimensions(csi_dev, &width, &height); sun6i_csi_capture_format(csi_dev, &pixelformat, &field); - hor_len = width; + hsize_len = width; + vsize_len = height; switch (pixelformat) { case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_VYUY: - dev_dbg(csi_dev->dev, - "Horizontal length should be 2 times of width for packed YUV formats!\n"); - hor_len = width * 2; + /* + * Horizontal length should be 2 times of width for packed + * YUV formats. + */ + hsize_len *= 2; break; default: break; } - regmap_write(csi_dev->regmap, SUN6I_CSI_CH_HSIZE_REG, - SUN6I_CSI_CH_HSIZE_LEN(hor_len) | + regmap_write(regmap, SUN6I_CSI_CH_HSIZE_REG, + SUN6I_CSI_CH_HSIZE_LEN(hsize_len) | SUN6I_CSI_CH_HSIZE_START(0)); - regmap_write(csi_dev->regmap, SUN6I_CSI_CH_VSIZE_REG, - SUN6I_CSI_CH_VSIZE_LEN(height) | + + regmap_write(regmap, SUN6I_CSI_CH_VSIZE_REG, + SUN6I_CSI_CH_VSIZE_LEN(vsize_len) | SUN6I_CSI_CH_VSIZE_START(0)); switch (pixelformat) { - case V4L2_PIX_FMT_NV12_16L16: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - bytesperline_y = width; - bytesperline_c = width; + case V4L2_PIX_FMT_RGB565X: + luma_line = width * 2; break; - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - bytesperline_y = width; - bytesperline_c = width / 2; + case V4L2_PIX_FMT_NV12_16L16: + luma_line = width; + chroma_line = width; break; - case V4L2_PIX_FMT_YUV422P: - bytesperline_y = width; - bytesperline_c = width / 2; + case V4L2_PIX_FMT_JPEG: + luma_line = width; break; - default: /* raw */ - dev_dbg(csi_dev->dev, - "Calculating pixelformat(0x%x)'s bytesperline as a packed format\n", - pixelformat); - bytesperline_y = (sun6i_csi_get_bpp(pixelformat) * - width) / 8; - bytesperline_c = 0; + default: + info = v4l2_format_info(pixelformat); + if (WARN_ON(!info)) + return; + + luma_line = width * info->bpp[0]; + + if (info->comp_planes > 1) + chroma_line = width * info->bpp[1] / info->hdiv; break; } - regmap_write(csi_dev->regmap, SUN6I_CSI_CH_BUF_LEN_REG, - SUN6I_CSI_CH_BUF_LEN_CHROMA_LINE(bytesperline_c) | - SUN6I_CSI_CH_BUF_LEN_LUMA_LINE(bytesperline_y)); + regmap_write(regmap, SUN6I_CSI_CH_BUF_LEN_REG, + SUN6I_CSI_CH_BUF_LEN_CHROMA_LINE(chroma_line) | + SUN6I_CSI_CH_BUF_LEN_LUMA_LINE(luma_line)); } static void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev) From patchwork Fri Mar 11 14:35:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778139 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6E167C433F5 for ; Fri, 11 Mar 2022 14:37:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349492AbiCKOiM (ORCPT ); Fri, 11 Mar 2022 09:38:12 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59388 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349573AbiCKOhj (ORCPT ); Fri, 11 Mar 2022 09:37:39 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 733531C9468; Fri, 11 Mar 2022 06:36:32 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id B8262240008; Fri, 11 Mar 2022 14:36:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009390; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=IWC8UV10AFRXwQVKEyuL0EJsXyCUBUdFgxYAqrwrG+w=; b=ZCpuy2uQpzT7nmclRYOAvCI4yYxIehY5CC+w+Fx9ZVy37XB7uf85+3MDo3uFUU8NfDwp4P Vkm0Bhnk+rMjZtw+9CCtIuN6aQQzBVS8qMydjs/RaMRDlC7rTSbOvDYBoZPHclD0Y4RECc VlLtRYr4ob/EgBFxwB1wEuRCR+ERS9WnNXJ41teXOyVUU6Ia3PLo99moVmwtOMKVjdDEpj CrWFEmLANeE4mdMhokVO9zqj4ePPRxa7Fc+4MH/Jbu9/YyStnc1ir0TBdr3Z/2raAVYWzD ifc90MDDH4jmPWKTJrkM6OUmRNF6KC+n3GiVeozf2Gyp2JewjIrZPByGdezrdA== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 27/46] media: sun6i-csi: Add bridge dimensions and format helpers Date: Fri, 11 Mar 2022 15:35:13 +0100 Message-Id: <20220311143532.265091-28-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Introduce new helpers to ease getting information about the bridge. Signed-off-by: Paul Kocialkowski --- .../sunxi/sun6i-csi/sun6i_csi_bridge.c | 20 +++++++++++++++++++ .../sunxi/sun6i-csi/sun6i_csi_bridge.h | 7 +++++++ 2 files changed, 27 insertions(+) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c index 33309423d1e6..8009b281cbb6 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c @@ -12,6 +12,26 @@ #include "sun6i_csi.h" #include "sun6i_csi_bridge.h" +/* Helpers */ + +void sun6i_csi_bridge_dimensions(struct sun6i_csi_device *csi_dev, + unsigned int *width, unsigned int *height) +{ + if (width) + *width = csi_dev->bridge.mbus_format.width; + if (height) + *height = csi_dev->bridge.mbus_format.height; +} + +void sun6i_csi_bridge_format(struct sun6i_csi_device *csi_dev, + u32 *mbus_code, u32 *field) +{ + if (mbus_code) + *mbus_code = csi_dev->bridge.mbus_format.code; + if (field) + *field = csi_dev->bridge.mbus_format.field; +} + /* Format */ static const u32 sun6i_csi_bridge_mbus_codes[] = { diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h index 55be292d308c..ee90ff6a6f75 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h @@ -42,6 +42,13 @@ struct sun6i_csi_bridge { struct sun6i_csi_bridge_source *source; }; +/* Helpers */ + +void sun6i_csi_bridge_dimensions(struct sun6i_csi_device *csi_dev, + unsigned int *width, unsigned int *height); +void sun6i_csi_bridge_format(struct sun6i_csi_device *csi_dev, + u32 *mbus_code, u32 *field); + /* Bridge */ int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev); From patchwork Fri Mar 11 14:35:14 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778137 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4E2E9C43217 for ; Fri, 11 Mar 2022 14:37:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349616AbiCKOiK (ORCPT ); Fri, 11 Mar 2022 09:38:10 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59718 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349475AbiCKOhm (ORCPT ); Fri, 11 Mar 2022 09:37:42 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BD4D01C9476; Fri, 11 Mar 2022 06:36:33 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 0B290240014; Fri, 11 Mar 2022 14:36:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009392; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=dfjOJcHpbpHzSsr3B+Uk57gfLY4CzVGb/sVf8hEV314=; b=CoohK87AlPaywMzwJmaIsttnGN3W+d8K2ktXSOxHp1CIxMN4E+poHxiPpiowTiY1VVErz7 t4cd0SYFa/qXFEApLu/8MmRg6dcRhWc6EcJVN9HTyU+HEqBPdQdzU3T6Vhp2/K1hYhPCdy nMJBAB/yHeqtmHdsfkRC5Lzh7vrs05SldMCq5Vx8B9rseXYnBF18bPGAbkOVuUNiR90rvh 6toF/Pr1vxg1Tp6+Q7bEh/sL44SQ0dWtidYqgcP2fHsKtg+cn3adN4uGaxCs86BBL9h4Ds lHyA4U7IU2zS2jea8F6i/mipxj4ZOl8K3fvFgAhC7PGqy8vXDhFR7rcBvfGYsw== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 28/46] media: sun6i-csi: Get mbus code from bridge instead of storing it Date: Fri, 11 Mar 2022 15:35:14 +0100 Message-Id: <20220311143532.265091-29-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Another instance of removing a duplicated variable and using common helpers instead. Signed-off-by: Paul Kocialkowski --- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 18 +++++------------- .../sunxi/sun6i-csi/sun6i_csi_capture.h | 1 - 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index f977b89dcea2..12c02408d18e 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -17,6 +17,7 @@ #include #include "sun6i_csi.h" +#include "sun6i_csi_bridge.h" #include "sun6i_csi_capture.h" #include "sun6i_csi_reg.h" @@ -455,20 +456,20 @@ sun6i_csi_capture_configure_interface(struct sun6i_csi_device *csi_dev) static void sun6i_csi_capture_configure_format(struct sun6i_csi_device *csi_dev) { - struct sun6i_csi_capture *capture = &csi_dev->capture; - u32 pixelformat, field; + u32 mbus_code, pixelformat, field; u32 cfg = 0; u32 val; sun6i_csi_capture_format(csi_dev, &pixelformat, &field); + sun6i_csi_bridge_format(csi_dev, &mbus_code, NULL); - val = get_csi_input_format(csi_dev, capture->mbus_code, pixelformat); + val = get_csi_input_format(csi_dev, mbus_code, pixelformat); cfg |= SUN6I_CSI_CH_CFG_INPUT_FMT(val); val = get_csi_output_format(csi_dev, pixelformat, field); cfg |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(val); - val = get_csi_input_seq(csi_dev, capture->mbus_code, pixelformat); + val = get_csi_input_seq(csi_dev, mbus_code, pixelformat); cfg |= SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(val); if (field == V4L2_FIELD_TOP) @@ -739,11 +740,6 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, if (ret < 0) goto error_state; - if (capture->mbus_code == 0) { - ret = -EINVAL; - goto error_media_pipeline; - } - subdev = sun6i_csi_capture_remote_subdev(capture, NULL); if (!subdev) { ret = -EINVAL; @@ -1067,8 +1063,6 @@ static int sun6i_csi_capture_link_validate(struct media_link *link) struct v4l2_subdev_format source_fmt; int ret; - capture->mbus_code = 0; - if (!media_entity_remote_pad(link->sink->entity->pads)) { dev_info(csi_dev->dev, "capture node %s pad not connected\n", vdev->name); @@ -1100,8 +1094,6 @@ static int sun6i_csi_capture_link_validate(struct media_link *link) return -EPIPE; } - capture->mbus_code = source_fmt.format.code; - return 0; } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h index 02bdf45f7ca5..3b9759e1563d 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h @@ -39,7 +39,6 @@ struct sun6i_csi_capture { struct media_pad pad; struct v4l2_format format; - u32 mbus_code; }; void sun6i_csi_capture_dimensions(struct sun6i_csi_device *csi_dev, From patchwork Fri Mar 11 14:35:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778138 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7B831C433FE for ; Fri, 11 Mar 2022 14:37:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349500AbiCKOiL (ORCPT ); Fri, 11 Mar 2022 09:38:11 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59726 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349585AbiCKOhm (ORCPT ); Fri, 11 Mar 2022 09:37:42 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E6C2C1C9477; Fri, 11 Mar 2022 06:36:34 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 5AD9B24001A; Fri, 11 Mar 2022 14:36:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009393; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zhIUG9Wb8r7xhMYMWkvu01J+yj35PnUIfRFm0qkzrGk=; b=XU8Opjovr7Am4L2agxh/qXtsB+DDuGgE30d8Ah8lz7ApGYQpGzV9+JpyDDutnMZPBwKsj5 Awt/IR38qZQLi60WMqjCOb3gMaY+DU9WkVSLoixyAsCPvnT93EjySGt2TBgRKXZAGvAZNQ u4PFoVjrutggpHwxtzQjdtFW7u9Ia4FLRUgEIN7AG35hUi+0TMGk/ZEUyaRwqz2YvXVJdt VXHN+VB0Gz9ZCJCO2edTps5HrRx7H9IaKLxvjrOUg6oMVqlaU4QJRk7cOFHvuE8Cw4aKbC bu1ySGYZMJ97CXiMpxzUYzGNPtjmhG9qFWQ+BQ5oE33iPJMGx4liV71d+itkqw== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 29/46] media: sun6i-csi: Tidy capture configure code Date: Fri, 11 Mar 2022 15:35:15 +0100 Message-Id: <20220311143532.265091-30-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Some misc code cleanups and preparation for upcoming changes. Signed-off-by: Paul Kocialkowski --- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 105 ++++++++---------- 1 file changed, 46 insertions(+), 59 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 12c02408d18e..726416d98c46 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -353,133 +353,120 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_device *csi_dev, static void sun6i_csi_capture_configure_interface(struct sun6i_csi_device *csi_dev) { + struct device *dev = csi_dev->dev; + struct regmap *regmap = csi_dev->regmap; struct v4l2_fwnode_endpoint *endpoint = &csi_dev->bridge.source->endpoint; + unsigned char bus_width = endpoint->bus.parallel.bus_width; + unsigned int flags = endpoint->bus.parallel.flags; u32 pixelformat, field; - unsigned char bus_width; - u32 flags; - u32 cfg = 0; - bool input_interlaced = false; + u32 value = SUN6I_CSI_IF_CFG_IF_CSI; sun6i_csi_capture_format(csi_dev, &pixelformat, &field); if (field == V4L2_FIELD_INTERLACED || field == V4L2_FIELD_INTERLACED_TB || field == V4L2_FIELD_INTERLACED_BT) - input_interlaced = true; - - bus_width = endpoint->bus.parallel.bus_width; - - if (input_interlaced) - cfg |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED | - SUN6I_CSI_IF_CFG_FIELD_DT_PCLK_SHIFT(1) | - SUN6I_CSI_IF_CFG_FIELD_DT_FIELD_VSYNC; + value |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED | + SUN6I_CSI_IF_CFG_FIELD_DT_PCLK_SHIFT(1) | + SUN6I_CSI_IF_CFG_FIELD_DT_FIELD_VSYNC; else - cfg |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE; + value |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE; switch (endpoint->bus_type) { case V4L2_MBUS_PARALLEL: - cfg |= SUN6I_CSI_IF_CFG_IF_CSI; - - flags = endpoint->bus.parallel.flags; - if (bus_width == 16) - cfg |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_COMBINED; + value |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_COMBINED; else - cfg |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_RAW; + value |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_RAW; if (flags & V4L2_MBUS_FIELD_EVEN_LOW) - cfg |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE; + value |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE; else - cfg |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE; + value |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE; if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - cfg |= SUN6I_CSI_IF_CFG_VREF_POL_NEGATIVE; + value |= SUN6I_CSI_IF_CFG_VREF_POL_NEGATIVE; else - cfg |= SUN6I_CSI_IF_CFG_VREF_POL_POSITIVE; + value |= SUN6I_CSI_IF_CFG_VREF_POL_POSITIVE; if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - cfg |= SUN6I_CSI_IF_CFG_HREF_POL_NEGATIVE; + value |= SUN6I_CSI_IF_CFG_HREF_POL_NEGATIVE; else - cfg |= SUN6I_CSI_IF_CFG_HREF_POL_POSITIVE; + value |= SUN6I_CSI_IF_CFG_HREF_POL_POSITIVE; if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) - cfg |= SUN6I_CSI_IF_CFG_CLK_POL_RISING; + value |= SUN6I_CSI_IF_CFG_CLK_POL_RISING; else - cfg |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING; + value |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING; break; case V4L2_MBUS_BT656: - cfg |= SUN6I_CSI_IF_CFG_IF_CSI; - - flags = endpoint->bus.parallel.flags; - if (bus_width == 16) - cfg |= SUN6I_CSI_IF_CFG_IF_CSI_BT1120; + value |= SUN6I_CSI_IF_CFG_IF_CSI_BT1120; else - cfg |= SUN6I_CSI_IF_CFG_IF_CSI_BT656; + value |= SUN6I_CSI_IF_CFG_IF_CSI_BT656; if (flags & V4L2_MBUS_FIELD_EVEN_LOW) - cfg |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE; + value |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE; else - cfg |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE; + value |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE; if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) - cfg |= SUN6I_CSI_IF_CFG_CLK_POL_RISING; + value |= SUN6I_CSI_IF_CFG_CLK_POL_RISING; else - cfg |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING; + value |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING; break; default: - dev_warn(csi_dev->dev, "Unsupported bus type: %d\n", - endpoint->bus_type); + dev_warn(dev, "unsupported bus type: %d\n", endpoint->bus_type); break; } switch (bus_width) { case 8: - cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_8; + /* 16-bit YUV formats use a doubled width in 8-bit mode. */ + case 16: + value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_8; break; case 10: - cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_10; + value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_10; break; case 12: - cfg |= SUN6I_CSI_IF_CFG_DATA_WIDTH_12; - break; - case 16: /* No need to configure DATA_WIDTH for 16bit */ + value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_12; break; default: - dev_warn(csi_dev->dev, "Unsupported bus width: %u\n", bus_width); + dev_warn(dev, "unsupported bus width: %u\n", bus_width); break; } - regmap_write(csi_dev->regmap, SUN6I_CSI_IF_CFG_REG, cfg); + regmap_write(regmap, SUN6I_CSI_IF_CFG_REG, value); } static void sun6i_csi_capture_configure_format(struct sun6i_csi_device *csi_dev) { + struct regmap *regmap = csi_dev->regmap; u32 mbus_code, pixelformat, field; - u32 cfg = 0; - u32 val; + u8 input_format, input_yuv_seq, output_format; + u32 value = 0; sun6i_csi_capture_format(csi_dev, &pixelformat, &field); sun6i_csi_bridge_format(csi_dev, &mbus_code, NULL); - val = get_csi_input_format(csi_dev, mbus_code, pixelformat); - cfg |= SUN6I_CSI_CH_CFG_INPUT_FMT(val); - - val = get_csi_output_format(csi_dev, pixelformat, field); - cfg |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(val); + input_format = get_csi_input_format(csi_dev, mbus_code, pixelformat); + input_yuv_seq = get_csi_input_seq(csi_dev, mbus_code, pixelformat); + output_format = get_csi_output_format(csi_dev, pixelformat, field); - val = get_csi_input_seq(csi_dev, mbus_code, pixelformat); - cfg |= SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(val); + value |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(output_format); + value |= SUN6I_CSI_CH_CFG_INPUT_FMT(input_format); + value |= SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(input_yuv_seq); if (field == V4L2_FIELD_TOP) - cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD0; + value |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD0; else if (field == V4L2_FIELD_BOTTOM) - cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD1; + value |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD1; else - cfg |= SUN6I_CSI_CH_CFG_FIELD_SEL_EITHER; + value |= SUN6I_CSI_CH_CFG_FIELD_SEL_EITHER; - regmap_write(csi_dev->regmap, SUN6I_CSI_CH_CFG_REG, cfg); + regmap_write(regmap, SUN6I_CSI_CH_CFG_REG, value); } static void sun6i_csi_capture_configure_window(struct sun6i_csi_device *csi_dev) From patchwork Fri Mar 11 14:35:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778136 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 41832C4332F for ; Fri, 11 Mar 2022 14:37:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349611AbiCKOiI (ORCPT ); Fri, 11 Mar 2022 09:38:08 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59826 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349599AbiCKOho (ORCPT ); Fri, 11 Mar 2022 09:37:44 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 861481C9B46; Fri, 11 Mar 2022 06:36:36 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 91A2B24001C; Fri, 11 Mar 2022 14:36:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009395; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HO2JlnDQp7FZQeLXmizlbjiMqhTC6RztsXTEg90LkTM=; b=Av+Bt5diHKu+q0MljJl5coLNfNBGORh5crcRoE3Z3Lq01uG8evDnvF+d2qvS1QMiCxszr0 +2WZyldam9EsGwm9F9rI6aEv+/lR6VGiEye9A5iEguvfGyxy6/K+sD8AffKw2rwU0wf+Wf k44gsAvLxvbDpMfrSWtj8Pocvg6skP5bHHNsWjaAF4p8LAqTCpDAWwnpi3w3h87qknrcXJ Za0c+FNRGA1rkQF+++RKnl1D5k27cIX5rh8/rttKPucdOGgrC3CaEaLgM3P2zHfQsKavTr 6AYd2HB+WUVGKu1YqijBWAWV3wz1LyiJSKGQ3yGsLtjIRIeH/iZjz/BB6IxU+g== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 30/46] media: sun6i-csi: Introduce bridge format structure, list and helper Date: Fri, 11 Mar 2022 15:35:16 +0100 Message-Id: <20220311143532.265091-31-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Introduce a more informative format list for the bridge, with information about how to configure the input. This separation will later be useful when using the bridge standalone (without capture) for the isp workflow. Signed-off-by: Paul Kocialkowski --- .../sunxi/sun6i-csi/sun6i_csi_bridge.c | 169 ++++++++++++++---- .../sunxi/sun6i-csi/sun6i_csi_bridge.h | 12 ++ 2 files changed, 145 insertions(+), 36 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c index 8009b281cbb6..24a34e1a1dfd 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c @@ -11,6 +11,7 @@ #include "sun6i_csi.h" #include "sun6i_csi_bridge.h" +#include "sun6i_csi_reg.h" /* Helpers */ @@ -34,47 +35,143 @@ void sun6i_csi_bridge_format(struct sun6i_csi_device *csi_dev, /* Format */ -static const u32 sun6i_csi_bridge_mbus_codes[] = { +static const struct sun6i_csi_bridge_format sun6i_csi_bridge_formats[] = { /* Bayer */ - MEDIA_BUS_FMT_SBGGR8_1X8, - MEDIA_BUS_FMT_SGBRG8_1X8, - MEDIA_BUS_FMT_SGRBG8_1X8, - MEDIA_BUS_FMT_SRGGB8_1X8, - MEDIA_BUS_FMT_SBGGR10_1X10, - MEDIA_BUS_FMT_SGBRG10_1X10, - MEDIA_BUS_FMT_SGRBG10_1X10, - MEDIA_BUS_FMT_SRGGB10_1X10, - MEDIA_BUS_FMT_SBGGR12_1X12, - MEDIA_BUS_FMT_SGBRG12_1X12, - MEDIA_BUS_FMT_SGRBG12_1X12, - MEDIA_BUS_FMT_SRGGB12_1X12, + { + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .input_format = SUN6I_CSI_INPUT_FMT_RAW, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .input_format = SUN6I_CSI_INPUT_FMT_RAW, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .input_format = SUN6I_CSI_INPUT_FMT_RAW, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .input_format = SUN6I_CSI_INPUT_FMT_RAW, + }, + { + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .input_format = SUN6I_CSI_INPUT_FMT_RAW, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .input_format = SUN6I_CSI_INPUT_FMT_RAW, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .input_format = SUN6I_CSI_INPUT_FMT_RAW, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .input_format = SUN6I_CSI_INPUT_FMT_RAW, + }, + { + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + .input_format = SUN6I_CSI_INPUT_FMT_RAW, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + .input_format = SUN6I_CSI_INPUT_FMT_RAW, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + .input_format = SUN6I_CSI_INPUT_FMT_RAW, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + .input_format = SUN6I_CSI_INPUT_FMT_RAW, + }, /* RGB */ - MEDIA_BUS_FMT_RGB565_2X8_LE, - MEDIA_BUS_FMT_RGB565_2X8_BE, + { + .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .input_format = SUN6I_CSI_INPUT_FMT_RAW, + }, + { + .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_BE, + .input_format = SUN6I_CSI_INPUT_FMT_RAW, + }, /* YUV422 */ - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_YVYU8_2X8, - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_VYUY8_2X8, - MEDIA_BUS_FMT_YUYV8_1X16, - MEDIA_BUS_FMT_UYVY8_1X16, - MEDIA_BUS_FMT_YVYU8_1X16, - MEDIA_BUS_FMT_UYVY8_1X16, - MEDIA_BUS_FMT_VYUY8_1X16, + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + .input_format = SUN6I_CSI_INPUT_FMT_YUV422, + .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_YUYV, + .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_YVYU, + }, + { + .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, + .input_format = SUN6I_CSI_INPUT_FMT_YUV422, + .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_UYVY, + .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_VYUY, + }, + { + .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, + .input_format = SUN6I_CSI_INPUT_FMT_YUV422, + .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_YVYU, + .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_YUYV, + }, + { + .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, + .input_format = SUN6I_CSI_INPUT_FMT_YUV422, + .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_UYVY, + .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_VYUY, + }, + { + .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, + .input_format = SUN6I_CSI_INPUT_FMT_YUV422, + .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_VYUY, + .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_UYVY, + }, + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, + .input_format = SUN6I_CSI_INPUT_FMT_YUV422, + .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_YUYV, + .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_YVYU, + }, + { + .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, + .input_format = SUN6I_CSI_INPUT_FMT_YUV422, + .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_UYVY, + .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_VYUY, + }, + { + .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, + .input_format = SUN6I_CSI_INPUT_FMT_YUV422, + .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_YVYU, + .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_YUYV, + }, + { + .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, + .input_format = SUN6I_CSI_INPUT_FMT_YUV422, + .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_UYVY, + .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_VYUY, + }, + { + .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, + .input_format = SUN6I_CSI_INPUT_FMT_YUV422, + .input_yuv_seq = SUN6I_CSI_INPUT_YUV_SEQ_VYUY, + .input_yuv_seq_invert = SUN6I_CSI_INPUT_YUV_SEQ_UYVY, + }, /* Compressed */ - MEDIA_BUS_FMT_JPEG_1X8, + { + .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, + .input_format = SUN6I_CSI_INPUT_FMT_RAW, + }, }; -static bool sun6i_csi_bridge_mbus_code_check(u32 mbus_code) +const struct sun6i_csi_bridge_format * +sun6i_csi_bridge_format_find(u32 mbus_code) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(sun6i_csi_bridge_mbus_codes); i++) - if (sun6i_csi_bridge_mbus_codes[i] == mbus_code) - return true; + for (i = 0; i < ARRAY_SIZE(sun6i_csi_bridge_formats); i++) + if (sun6i_csi_bridge_formats[i].mbus_code == mbus_code) + return &sun6i_csi_bridge_formats[i]; - return false; + return NULL; } /* V4L2 Subdev */ @@ -117,8 +214,8 @@ static const struct v4l2_subdev_video_ops sun6i_csi_bridge_video_ops = { static void sun6i_csi_bridge_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format) { - if (!sun6i_csi_bridge_mbus_code_check(mbus_format->code)) - mbus_format->code = sun6i_csi_bridge_mbus_codes[0]; + if (!sun6i_csi_bridge_format_find(mbus_format->code)) + mbus_format->code = sun6i_csi_bridge_formats[0].mbus_code; mbus_format->field = V4L2_FIELD_NONE; mbus_format->colorspace = V4L2_COLORSPACE_RAW; @@ -137,7 +234,7 @@ static int sun6i_csi_bridge_init_cfg(struct v4l2_subdev *subdev, mutex_lock(lock); - mbus_format->code = sun6i_csi_bridge_mbus_codes[0]; + mbus_format->code = sun6i_csi_bridge_formats[0].mbus_code; mbus_format->width = 1280; mbus_format->height = 720; @@ -153,10 +250,10 @@ sun6i_csi_bridge_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(sun6i_csi_bridge_mbus_codes)) + if (code_enum->index >= ARRAY_SIZE(sun6i_csi_bridge_formats)) return -EINVAL; - code_enum->code = sun6i_csi_bridge_mbus_codes[code_enum->index]; + code_enum->code = sun6i_csi_bridge_formats[code_enum->index].mbus_code; return 0; } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h index ee90ff6a6f75..66fe7942b191 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h @@ -20,6 +20,13 @@ enum sun6i_csi_bridge_pad { struct sun6i_csi_device; +struct sun6i_csi_bridge_format { + u32 mbus_code; + u8 input_format; + u8 input_yuv_seq; + u8 input_yuv_seq_invert; +}; + struct sun6i_csi_bridge_source { struct v4l2_subdev *subdev; struct v4l2_fwnode_endpoint endpoint; @@ -49,6 +56,11 @@ void sun6i_csi_bridge_dimensions(struct sun6i_csi_device *csi_dev, void sun6i_csi_bridge_format(struct sun6i_csi_device *csi_dev, u32 *mbus_code, u32 *field); +/* Format */ + +const struct sun6i_csi_bridge_format * +sun6i_csi_bridge_format_find(u32 mbus_code); + /* Bridge */ int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev); From patchwork Fri Mar 11 14:35:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778135 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A8210C433FE for ; Fri, 11 Mar 2022 14:37:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349505AbiCKOiI (ORCPT ); Fri, 11 Mar 2022 09:38:08 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59874 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349603AbiCKOhp (ORCPT ); Fri, 11 Mar 2022 09:37:45 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2942E1C8DAD; Fri, 11 Mar 2022 06:36:37 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 353BA24000B; Fri, 11 Mar 2022 14:36:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009396; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/dleKHs/Gfe5ikm2w4BzIkLPMJhGodkQw0WeqFhheKc=; b=mOhPcTq3H9Fn9vV2nAZH62dbEzZYriLrilL6rPAixq8wlcfe5LkSazdZ4Xjyg64QWh2Bs4 9gLuR2tdEIKNt9ftVuE/ZZUdU8smwxU+5vDAAy+kQml72dYnt8xAgB1EcIEGGZ9uODpGOn JI6005uAhoYuysEuHV2MqUfp2kXJGiI6bmtzQ/IZIfR5/zC91AgzfZOppxBVHBi1lOy7Yt e8ilA4bHY5GdcfWFh97yA/qoKZmGkJtqwYysxDltbw6uQ3n7Un/Lzwbxu4uQJdGT7xAPRr dsAYt92CNCNwDQRYAWb5dRDXYBsAsCQhJx4hFX23BFuLvvCKmxmSOv4slAY5Zw== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 31/46] media: sun6i-csi: Introduce capture format structure, list and helper Date: Fri, 11 Mar 2022 15:35:17 +0100 Message-Id: <20220311143532.265091-32-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Add a table that describes each pixel format and associated output register configuration with necessary tweaks. It will be used later on to configure the hardware. Signed-off-by: Paul Kocialkowski --- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 199 ++++++++++++++---- .../sunxi/sun6i-csi/sun6i_csi_capture.h | 12 ++ 2 files changed, 175 insertions(+), 36 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 726416d98c46..8e71c81cd54f 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -60,45 +60,171 @@ sun6i_csi_capture_remote_subdev(struct sun6i_csi_capture *capture, u32 *pad) /* Format */ -static const u32 sun6i_csi_capture_formats[] = { - V4L2_PIX_FMT_SBGGR8, - V4L2_PIX_FMT_SGBRG8, - V4L2_PIX_FMT_SGRBG8, - V4L2_PIX_FMT_SRGGB8, - V4L2_PIX_FMT_SBGGR10, - V4L2_PIX_FMT_SGBRG10, - V4L2_PIX_FMT_SGRBG10, - V4L2_PIX_FMT_SRGGB10, - V4L2_PIX_FMT_SBGGR12, - V4L2_PIX_FMT_SGBRG12, - V4L2_PIX_FMT_SGRBG12, - V4L2_PIX_FMT_SRGGB12, - V4L2_PIX_FMT_YUYV, - V4L2_PIX_FMT_YVYU, - V4L2_PIX_FMT_UYVY, - V4L2_PIX_FMT_VYUY, - V4L2_PIX_FMT_NV12_16L16, - V4L2_PIX_FMT_NV12, - V4L2_PIX_FMT_NV21, - V4L2_PIX_FMT_YUV420, - V4L2_PIX_FMT_YVU420, - V4L2_PIX_FMT_NV16, - V4L2_PIX_FMT_NV61, - V4L2_PIX_FMT_YUV422P, - V4L2_PIX_FMT_RGB565, - V4L2_PIX_FMT_RGB565X, - V4L2_PIX_FMT_JPEG, +static const struct sun6i_csi_capture_format sun6i_csi_capture_formats[] = { + /* Bayer */ + { + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8, + }, + { + .pixelformat = V4L2_PIX_FMT_SGBRG8, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8, + }, + { + .pixelformat = V4L2_PIX_FMT_SGRBG8, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8, + }, + { + .pixelformat = V4L2_PIX_FMT_SRGGB8, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8, + }, + { + .pixelformat = V4L2_PIX_FMT_SBGGR10, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10, + }, + { + .pixelformat = V4L2_PIX_FMT_SGBRG10, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10, + }, + { + .pixelformat = V4L2_PIX_FMT_SGRBG10, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10, + }, + { + .pixelformat = V4L2_PIX_FMT_SRGGB10, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_10, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_10, + }, + { + .pixelformat = V4L2_PIX_FMT_SBGGR12, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12, + }, + { + .pixelformat = V4L2_PIX_FMT_SGBRG12, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12, + }, + { + .pixelformat = V4L2_PIX_FMT_SGRBG12, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12, + }, + { + .pixelformat = V4L2_PIX_FMT_SRGGB12, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_12, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_12, + }, + /* RGB */ + { + .pixelformat = V4L2_PIX_FMT_RGB565, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RGB565, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RGB565, + }, + { + .pixelformat = V4L2_PIX_FMT_RGB565X, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RGB565, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RGB565, + }, + /* YUV422 */ + { + .pixelformat = V4L2_PIX_FMT_YUYV, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8, + .input_format_raw = true, + .hsize_len_factor = 2, + }, + { + .pixelformat = V4L2_PIX_FMT_YVYU, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8, + .input_format_raw = true, + .hsize_len_factor = 2, + }, + { + .pixelformat = V4L2_PIX_FMT_UYVY, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8, + .input_format_raw = true, + .hsize_len_factor = 2, + }, + { + .pixelformat = V4L2_PIX_FMT_VYUY, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8, + .input_format_raw = true, + .hsize_len_factor = 2, + }, + { + .pixelformat = V4L2_PIX_FMT_NV16, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422SP, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422SP, + }, + { + .pixelformat = V4L2_PIX_FMT_NV61, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422SP, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422SP, + .input_yuv_seq_invert = true, + }, + { + .pixelformat = V4L2_PIX_FMT_YUV422P, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV422P, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV422P, + }, + /* YUV420 */ + { + .pixelformat = V4L2_PIX_FMT_NV12_16L16, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420MB, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420MB, + }, + { + .pixelformat = V4L2_PIX_FMT_NV12, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420SP, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420SP, + }, + { + .pixelformat = V4L2_PIX_FMT_NV21, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420SP, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420SP, + .input_yuv_seq_invert = true, + }, + + { + .pixelformat = V4L2_PIX_FMT_YUV420, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420P, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420P, + }, + { + .pixelformat = V4L2_PIX_FMT_YVU420, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_YUV420P, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_YUV420P, + .input_yuv_seq_invert = true, + }, + /* Compressed */ + { + .pixelformat = V4L2_PIX_FMT_JPEG, + .output_format_frame = SUN6I_CSI_OUTPUT_FMT_FRAME_RAW_8, + .output_format_field = SUN6I_CSI_OUTPUT_FMT_FIELD_RAW_8, + }, }; -static bool sun6i_csi_capture_format_check(u32 format) +const +struct sun6i_csi_capture_format *sun6i_csi_capture_format_find(u32 pixelformat) { unsigned int i; for (i = 0; i < ARRAY_SIZE(sun6i_csi_capture_formats); i++) - if (sun6i_csi_capture_formats[i] == format) - return true; + if (sun6i_csi_capture_formats[i].pixelformat == pixelformat) + return &sun6i_csi_capture_formats[i]; - return false; + return NULL; } /* Capture */ @@ -820,8 +946,9 @@ static void sun6i_csi_capture_format_prepare(struct v4l2_format *format) &pix_format->height, SUN6I_CSI_CAPTURE_HEIGHT_MIN, SUN6I_CSI_CAPTURE_HEIGHT_MAX, 1, 0); - if (!sun6i_csi_capture_format_check(pix_format->pixelformat)) - pix_format->pixelformat = sun6i_csi_capture_formats[0]; + if (!sun6i_csi_capture_format_find(pix_format->pixelformat)) + pix_format->pixelformat = + sun6i_csi_capture_formats[0].pixelformat; width = pix_format->width; height = pix_format->height; @@ -872,7 +999,7 @@ static int sun6i_csi_capture_enum_fmt(struct file *file, void *private, if (index >= ARRAY_SIZE(sun6i_csi_capture_formats)) return -EINVAL; - fmtdesc->pixelformat = sun6i_csi_capture_formats[index]; + fmtdesc->pixelformat = sun6i_csi_capture_formats[index].pixelformat; return 0; } @@ -1144,7 +1271,7 @@ int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev) /* V4L2 Format */ format->type = queue->type; - pix_format->pixelformat = sun6i_csi_capture_formats[0]; + pix_format->pixelformat = sun6i_csi_capture_formats[0].pixelformat; pix_format->width = 1280; pix_format->height = 720; pix_format->field = V4L2_FIELD_NONE; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h index 3b9759e1563d..4b1ff19edc2f 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h @@ -18,6 +18,15 @@ struct sun6i_csi_device; +struct sun6i_csi_capture_format { + u32 pixelformat; + u8 output_format_field; + u8 output_format_frame; + bool input_yuv_seq_invert; + bool input_format_raw; + u32 hsize_len_factor; +}; + #undef current struct sun6i_csi_capture_state { struct list_head queue; @@ -46,6 +55,9 @@ void sun6i_csi_capture_dimensions(struct sun6i_csi_device *csi_dev, void sun6i_csi_capture_format(struct sun6i_csi_device *csi_dev, u32 *pixelformat, u32 *field); +const +struct sun6i_csi_capture_format *sun6i_csi_capture_format_find(u32 pixelformat); + void sun6i_csi_capture_sync(struct sun6i_csi_device *csi_dev); void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev); From patchwork Fri Mar 11 14:35:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778134 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BFC60C433EF for ; Fri, 11 Mar 2022 14:37:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239087AbiCKOiF (ORCPT ); Fri, 11 Mar 2022 09:38:05 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59898 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349608AbiCKOhq (ORCPT ); Fri, 11 Mar 2022 09:37:46 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6A9721C944F; Fri, 11 Mar 2022 06:36:39 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 8FBBE240016; Fri, 11 Mar 2022 14:36:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009397; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=n2P1aWfSrF7aP6t1x/Wep2ylvFnH+m6GpmfYVvQ2bH0=; b=j3kaCtjlym1Vcpr+x43nHUGFA9I4uGhvmf+hZjnVCOnDGWt/aMGe7a3amUjBTc7FvKTXZN P+JdR/567u4lib4YkY3sQBvN3Dnij4d+PH+A2KJhEhR09yAvavG3COkDSnHdCFaQUul0hB 48PH6SNGHa51XVnH51+5OOvACxs0jFzi76MKh52j2nwSyJuHhpKHh6MAp0Q6L2hAlcClIZ CsLsVviM9ZfQblgWmWsJLk3QVOnNbjyUGKmlHLFa6VKvFc3v/7NpEOw8xnEfPM0/L53Xfi bdI3tlEbRhAR2gbv6vQpxMrji1sw3N3XyEQLmDE8jcK0u4my10qydAuBRsyLaQ== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 32/46] media: sun6i-csi: Configure registers from format tables Date: Fri, 11 Mar 2022 15:35:18 +0100 Message-Id: <20220311143532.265091-33-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Switch over to using the static format table descriptions to configure registers. Rework the hardware configuration helpers to leverage information from the format structures and benefit from their logic. Remove the previous dedicated helpers. The intention is to make the interaction between the different formats and the hardware side more visible and clear. Signed-off-by: Paul Kocialkowski --- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 210 +++--------------- .../platform/sunxi/sun6i-csi/sun6i_csi_reg.h | 55 ----- 2 files changed, 36 insertions(+), 229 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 8e71c81cd54f..1a5797454beb 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -319,163 +319,6 @@ sun6i_csi_capture_buffer_configure(struct sun6i_csi_device *csi_dev, } } -static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_device *csi_dev, - u32 mbus_code, u32 pixformat) -{ - /* non-YUV */ - if ((mbus_code & 0xF000) != 0x2000) - return CSI_INPUT_FORMAT_RAW; - - switch (pixformat) { - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_VYUY: - return CSI_INPUT_FORMAT_RAW; - default: - break; - } - - /* not support YUV420 input format yet */ - dev_dbg(csi_dev->dev, "Select YUV422 as default input format of CSI.\n"); - return CSI_INPUT_FORMAT_YUV422; -} - -static enum csi_output_fmt -get_csi_output_format(struct sun6i_csi_device *csi_dev, u32 pixformat, - u32 field) -{ - bool buf_interlaced = false; - - if (field == V4L2_FIELD_INTERLACED - || field == V4L2_FIELD_INTERLACED_TB - || field == V4L2_FIELD_INTERLACED_BT) - buf_interlaced = true; - - switch (pixformat) { - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8; - case V4L2_PIX_FMT_SBGGR10: - case V4L2_PIX_FMT_SGBRG10: - case V4L2_PIX_FMT_SGRBG10: - case V4L2_PIX_FMT_SRGGB10: - return buf_interlaced ? CSI_FRAME_RAW_10 : CSI_FIELD_RAW_10; - case V4L2_PIX_FMT_SBGGR12: - case V4L2_PIX_FMT_SGBRG12: - case V4L2_PIX_FMT_SGRBG12: - case V4L2_PIX_FMT_SRGGB12: - return buf_interlaced ? CSI_FRAME_RAW_12 : CSI_FIELD_RAW_12; - - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_VYUY: - return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8; - - case V4L2_PIX_FMT_NV12_16L16: - return buf_interlaced ? CSI_FRAME_MB_YUV420 : - CSI_FIELD_MB_YUV420; - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - return buf_interlaced ? CSI_FRAME_UV_CB_YUV420 : - CSI_FIELD_UV_CB_YUV420; - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - return buf_interlaced ? CSI_FRAME_PLANAR_YUV420 : - CSI_FIELD_PLANAR_YUV420; - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - return buf_interlaced ? CSI_FRAME_UV_CB_YUV422 : - CSI_FIELD_UV_CB_YUV422; - case V4L2_PIX_FMT_YUV422P: - return buf_interlaced ? CSI_FRAME_PLANAR_YUV422 : - CSI_FIELD_PLANAR_YUV422; - - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB565X: - return buf_interlaced ? CSI_FRAME_RGB565 : CSI_FIELD_RGB565; - - case V4L2_PIX_FMT_JPEG: - return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8; - - default: - dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x\n", pixformat); - break; - } - - return CSI_FIELD_RAW_8; -} - -static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_device *csi_dev, - u32 mbus_code, u32 pixformat) -{ - /* Input sequence does not apply to non-YUV formats */ - if ((mbus_code & 0xF000) != 0x2000) - return 0; - - switch (pixformat) { - case V4L2_PIX_FMT_NV12_16L16: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YUV422P: - switch (mbus_code) { - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_UYVY8_1X16: - return CSI_INPUT_SEQ_UYVY; - case MEDIA_BUS_FMT_VYUY8_2X8: - case MEDIA_BUS_FMT_VYUY8_1X16: - return CSI_INPUT_SEQ_VYUY; - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_YUYV8_1X16: - return CSI_INPUT_SEQ_YUYV; - case MEDIA_BUS_FMT_YVYU8_1X16: - case MEDIA_BUS_FMT_YVYU8_2X8: - return CSI_INPUT_SEQ_YVYU; - default: - dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n", - mbus_code); - break; - } - break; - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV61: - case V4L2_PIX_FMT_YVU420: - switch (mbus_code) { - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_UYVY8_1X16: - return CSI_INPUT_SEQ_VYUY; - case MEDIA_BUS_FMT_VYUY8_2X8: - case MEDIA_BUS_FMT_VYUY8_1X16: - return CSI_INPUT_SEQ_UYVY; - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_YUYV8_1X16: - return CSI_INPUT_SEQ_YVYU; - case MEDIA_BUS_FMT_YVYU8_1X16: - case MEDIA_BUS_FMT_YVYU8_2X8: - return CSI_INPUT_SEQ_YUYV; - default: - dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n", - mbus_code); - break; - } - break; - - case V4L2_PIX_FMT_YUYV: - return CSI_INPUT_SEQ_YUYV; - - default: - dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x, defaulting to YUYV\n", - pixformat); - break; - } - - return CSI_INPUT_SEQ_YUYV; -} - static void sun6i_csi_capture_configure_interface(struct sun6i_csi_device *csi_dev) { @@ -570,6 +413,8 @@ sun6i_csi_capture_configure_interface(struct sun6i_csi_device *csi_dev) static void sun6i_csi_capture_configure_format(struct sun6i_csi_device *csi_dev) { struct regmap *regmap = csi_dev->regmap; + const struct sun6i_csi_bridge_format *bridge_format; + const struct sun6i_csi_capture_format *capture_format; u32 mbus_code, pixelformat, field; u8 input_format, input_yuv_seq, output_format; u32 value = 0; @@ -577,9 +422,29 @@ static void sun6i_csi_capture_configure_format(struct sun6i_csi_device *csi_dev) sun6i_csi_capture_format(csi_dev, &pixelformat, &field); sun6i_csi_bridge_format(csi_dev, &mbus_code, NULL); - input_format = get_csi_input_format(csi_dev, mbus_code, pixelformat); - input_yuv_seq = get_csi_input_seq(csi_dev, mbus_code, pixelformat); - output_format = get_csi_output_format(csi_dev, pixelformat, field); + bridge_format = sun6i_csi_bridge_format_find(mbus_code); + if (WARN_ON(!bridge_format)) + return; + + input_format = bridge_format->input_format; + input_yuv_seq = bridge_format->input_yuv_seq; + + capture_format = sun6i_csi_capture_format_find(pixelformat); + if (WARN_ON(!capture_format)) + return; + + if (capture_format->input_format_raw) + input_format = SUN6I_CSI_INPUT_FMT_RAW; + + if (capture_format->input_yuv_seq_invert) + input_yuv_seq = bridge_format->input_yuv_seq_invert; + + if (field == V4L2_FIELD_INTERLACED || + field == V4L2_FIELD_INTERLACED_TB || + field == V4L2_FIELD_INTERLACED_BT) + output_format = capture_format->output_format_field; + else + output_format = capture_format->output_format_frame; value |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(output_format); value |= SUN6I_CSI_CH_CFG_INPUT_FMT(input_format); @@ -598,6 +463,7 @@ static void sun6i_csi_capture_configure_format(struct sun6i_csi_device *csi_dev) static void sun6i_csi_capture_configure_window(struct sun6i_csi_device *csi_dev) { struct regmap *regmap = csi_dev->regmap; + const struct sun6i_csi_capture_format *format; const struct v4l2_format_info *info; u32 hsize_len, vsize_len; u32 luma_line, chroma_line = 0; @@ -607,23 +473,19 @@ static void sun6i_csi_capture_configure_window(struct sun6i_csi_device *csi_dev) sun6i_csi_capture_dimensions(csi_dev, &width, &height); sun6i_csi_capture_format(csi_dev, &pixelformat, &field); + format = sun6i_csi_capture_format_find(pixelformat); + if (WARN_ON(!format)) + return; + hsize_len = width; vsize_len = height; - switch (pixelformat) { - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_VYUY: - /* - * Horizontal length should be 2 times of width for packed - * YUV formats. - */ - hsize_len *= 2; - break; - default: - break; - } + /* + * When using 8-bit raw input/output (for packed YUV), we need to adapt + * the width to account for the difference in bpp when it's not 8-bit. + */ + if (format->hsize_len_factor) + hsize_len *= format->hsize_len_factor; regmap_write(regmap, SUN6I_CSI_CH_HSIZE_REG, SUN6I_CSI_CH_HSIZE_LEN(hsize_len) | diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h index 9b0326d6ba3c..1e4a07f26d1d 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h @@ -180,59 +180,4 @@ #define SUN6I_CSI_CH_FIFO_STAT_REG 0x98 #define SUN6I_CSI_CH_PCLK_STAT_REG 0x9c -/* - * csi input data format - */ -enum csi_input_fmt { - CSI_INPUT_FORMAT_RAW = 0, - CSI_INPUT_FORMAT_YUV422 = 3, - CSI_INPUT_FORMAT_YUV420 = 4, -}; - -/* - * csi output data format - */ -enum csi_output_fmt { - /* only when input format is RAW */ - CSI_FIELD_RAW_8 = 0, - CSI_FIELD_RAW_10 = 1, - CSI_FIELD_RAW_12 = 2, - CSI_FIELD_RGB565 = 4, - CSI_FIELD_RGB888 = 5, - CSI_FIELD_PRGB888 = 6, - CSI_FRAME_RAW_8 = 8, - CSI_FRAME_RAW_10 = 9, - CSI_FRAME_RAW_12 = 10, - CSI_FRAME_RGB565 = 12, - CSI_FRAME_RGB888 = 13, - CSI_FRAME_PRGB888 = 14, - - /* only when input format is YUV422 */ - CSI_FIELD_PLANAR_YUV422 = 0, - CSI_FIELD_PLANAR_YUV420 = 1, - CSI_FRAME_PLANAR_YUV420 = 2, - CSI_FRAME_PLANAR_YUV422 = 3, - CSI_FIELD_UV_CB_YUV422 = 4, - CSI_FIELD_UV_CB_YUV420 = 5, - CSI_FRAME_UV_CB_YUV420 = 6, - CSI_FRAME_UV_CB_YUV422 = 7, - CSI_FIELD_MB_YUV422 = 8, - CSI_FIELD_MB_YUV420 = 9, - CSI_FRAME_MB_YUV420 = 10, - CSI_FRAME_MB_YUV422 = 11, - CSI_FIELD_UV_CB_YUV422_10 = 12, - CSI_FIELD_UV_CB_YUV420_10 = 13, -}; - -/* - * csi YUV input data sequence - */ -enum csi_input_seq { - /* only when input format is YUV422 */ - CSI_INPUT_SEQ_YUYV = 0, - CSI_INPUT_SEQ_YVYU, - CSI_INPUT_SEQ_UYVY, - CSI_INPUT_SEQ_VYUY, -}; - #endif /* __SUN6I_CSI_REG_H__ */ From patchwork Fri Mar 11 14:35:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778129 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A6902C433FE for ; Fri, 11 Mar 2022 14:36:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349539AbiCKOh4 (ORCPT ); Fri, 11 Mar 2022 09:37:56 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59940 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349621AbiCKOhs (ORCPT ); Fri, 11 Mar 2022 09:37:48 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 11EA31C9B54; Fri, 11 Mar 2022 06:36:40 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id F0B1124001D; Fri, 11 Mar 2022 14:36:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009399; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=vQABIwvDaCpqofKb9CpGithLajgEcAHeDnwzVHUYXaI=; b=FtLnherDaK/iMTfQbwEMef3cpQCslRn8UBFisXokonoOjVwKlk9f197i47VMoIowKS+bW6 u2EMK52AWPjUEOur84N545NHUspiuDQh7Wz1U9urClaKe8mwXmeI7xaQ0qUksgRE4pJOYM axo6zlZn0M4Lhl+WTMpFJ12t/iS1+H6m9/Y+vAO2OWCQ2kiZu7RjzBnFXSM4+SV2NzNP2f q3k0YhTSSwdfiDyR/a5dtVIaTkvg0yuEpw1YqabyKraSkGWtNiFYaPQguKajmB8rqays8k ouzQ1+4r0H1JfZjTQTNpAhVHFn4WBRygsLfqIYnvbZV5/tYnISkEyz5OTa2DFw== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 33/46] media: sun6i-csi: Introduce format match structure, list and helper Date: Fri, 11 Mar 2022 15:35:19 +0100 Message-Id: <20220311143532.265091-34-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Introduce a list of mbus/pixel format combinations that need an exact match between the two sides. This is the case when using raw input configuration. The list will be used to replace the sun6i_csi_is_format_supported combinatory helper. Signed-off-by: Paul Kocialkowski --- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 117 ++++++++++++++++++ .../sunxi/sun6i-csi/sun6i_csi_capture.h | 5 + 2 files changed, 122 insertions(+) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 1a5797454beb..91f2295cbdc6 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -227,6 +227,123 @@ struct sun6i_csi_capture_format *sun6i_csi_capture_format_find(u32 pixelformat) return NULL; } +/* RAW formats need an exact match between pixel and mbus formats. */ +static const +struct sun6i_csi_capture_format_match sun6i_csi_capture_format_matches[] = { + /* YUV420 */ + { + .pixelformat = V4L2_PIX_FMT_YUYV, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + }, + { + .pixelformat = V4L2_PIX_FMT_YUYV, + .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, + }, + { + .pixelformat = V4L2_PIX_FMT_YVYU, + .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, + }, + { + .pixelformat = V4L2_PIX_FMT_YVYU, + .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, + }, + { + .pixelformat = V4L2_PIX_FMT_UYVY, + .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, + }, + { + .pixelformat = V4L2_PIX_FMT_UYVY, + .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, + }, + { + .pixelformat = V4L2_PIX_FMT_VYUY, + .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, + }, + { + .pixelformat = V4L2_PIX_FMT_VYUY, + .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, + }, + /* RGB */ + { + .pixelformat = V4L2_PIX_FMT_RGB565, + .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, + }, + { + .pixelformat = V4L2_PIX_FMT_RGB565X, + .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_BE, + }, + /* Bayer */ + { + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + }, + { + .pixelformat = V4L2_PIX_FMT_SGBRG8, + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + }, + { + .pixelformat = V4L2_PIX_FMT_SGRBG8, + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + }, + { + .pixelformat = V4L2_PIX_FMT_SRGGB8, + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + }, + { + .pixelformat = V4L2_PIX_FMT_SBGGR10, + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + }, + { + .pixelformat = V4L2_PIX_FMT_SGBRG10, + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + }, + { + .pixelformat = V4L2_PIX_FMT_SGRBG10, + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + }, + { + .pixelformat = V4L2_PIX_FMT_SRGGB10, + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + }, + { + .pixelformat = V4L2_PIX_FMT_SBGGR12, + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + }, + { + .pixelformat = V4L2_PIX_FMT_SGBRG12, + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + }, + { + .pixelformat = V4L2_PIX_FMT_SGRBG12, + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + }, + { + .pixelformat = V4L2_PIX_FMT_SRGGB12, + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + }, + /* Compressed */ + { + .pixelformat = V4L2_PIX_FMT_JPEG, + .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, + }, +}; + +static bool sun6i_csi_capture_format_match(u32 pixelformat, u32 mbus_code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sun6i_csi_capture_format_matches); i++) { + const struct sun6i_csi_capture_format_match *match = + &sun6i_csi_capture_format_matches[i]; + + if (match->pixelformat == pixelformat && + match->mbus_code == mbus_code) + return true; + } + + return false; +} + /* Capture */ static void sun6i_csi_capture_irq_enable(struct sun6i_csi_device *csi_dev) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h index 4b1ff19edc2f..2605b16f091c 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h @@ -27,6 +27,11 @@ struct sun6i_csi_capture_format { u32 hsize_len_factor; }; +struct sun6i_csi_capture_format_match { + u32 pixelformat; + u32 mbus_code; +}; + #undef current struct sun6i_csi_capture_state { struct list_head queue; From patchwork Fri Mar 11 14:35:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778133 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 65C16C433F5 for ; Fri, 11 Mar 2022 14:37:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349584AbiCKOiC (ORCPT ); Fri, 11 Mar 2022 09:38:02 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59388 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349641AbiCKOht (ORCPT ); Fri, 11 Mar 2022 09:37:49 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D588F1C9B60; Fri, 11 Mar 2022 06:36:41 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 33EC7240005; Fri, 11 Mar 2022 14:36:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009400; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=o13zwXToanXRWvxJx5tqBQhdqfTqWHK/JcQXdJ0iy3w=; b=dYQSid6wU/pSpjJSKwyGztMoxkC2jZIfs9Q3qKV6/TC67kVAfQu7HqK1on5xWDzI/XiBiI 4QGciNMLhFRPi3aIXgkY4lM4eCUgdrSNR7luuvt3bi/V4vgYorjx4UCZO3fqnnCqNe66UY ZKGwtymOfEMzc3hnvgLlXg4rg8366Y2M58JiooZsDcWtjDRCAMTmWxgm3pcpn4+YLMMBf3 RO8+wjfTdMHTWBHcWlt59uuJF4QgEZdkkp6VTCnNisb9pq4irGnkG9F+8EtxfL0cM/JKqD YIqQh4lL7g4vM/6gid001016SnfwLv64oYOSqaZPgDJxxHUALXMMrh8Cju5MPA== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 34/46] media: sun6i-csi: Implement capture link validation with logic Date: Fri, 11 Mar 2022 15:35:20 +0100 Message-Id: <20220311143532.265091-35-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Rework the capture link validate implementation with actual logic that reflects the possibilities of the device instead of the combinatory helper functions, using the match list when needed. Remove the previous dedicated helper. Signed-off-by: Paul Kocialkowski --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 120 ------------------ .../platform/sunxi/sun6i-csi/sun6i_csi.h | 9 -- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 106 +++++++++------- 3 files changed, 62 insertions(+), 173 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index b0aa5cfdd681..298a0c74d12c 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -28,126 +28,6 @@ #include "sun6i_csi.h" #include "sun6i_csi_reg.h" -/* Helpers */ - -/* TODO add 10&12 bit YUV, RGB support */ -bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev, - u32 pixformat, u32 mbus_code) -{ - struct v4l2_fwnode_endpoint *endpoint = - &csi_dev->bridge.source->endpoint; - - /* - * Some video receivers have the ability to be compatible with - * 8bit and 16bit bus width. - * Identify the media bus format from device tree. - */ - if ((endpoint->bus_type == V4L2_MBUS_PARALLEL - || endpoint->bus_type == V4L2_MBUS_BT656) - && endpoint->bus.parallel.bus_width == 16) { - switch (pixformat) { - case V4L2_PIX_FMT_NV12_16L16: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - case V4L2_PIX_FMT_YUV422P: - switch (mbus_code) { - case MEDIA_BUS_FMT_UYVY8_1X16: - case MEDIA_BUS_FMT_VYUY8_1X16: - case MEDIA_BUS_FMT_YUYV8_1X16: - case MEDIA_BUS_FMT_YVYU8_1X16: - return true; - default: - dev_dbg(csi_dev->dev, - "Unsupported mbus code: 0x%x\n", - mbus_code); - break; - } - break; - default: - dev_dbg(csi_dev->dev, "Unsupported pixformat: 0x%x\n", - pixformat); - break; - } - return false; - } - - switch (pixformat) { - case V4L2_PIX_FMT_SBGGR8: - return (mbus_code == MEDIA_BUS_FMT_SBGGR8_1X8); - case V4L2_PIX_FMT_SGBRG8: - return (mbus_code == MEDIA_BUS_FMT_SGBRG8_1X8); - case V4L2_PIX_FMT_SGRBG8: - return (mbus_code == MEDIA_BUS_FMT_SGRBG8_1X8); - case V4L2_PIX_FMT_SRGGB8: - return (mbus_code == MEDIA_BUS_FMT_SRGGB8_1X8); - case V4L2_PIX_FMT_SBGGR10: - return (mbus_code == MEDIA_BUS_FMT_SBGGR10_1X10); - case V4L2_PIX_FMT_SGBRG10: - return (mbus_code == MEDIA_BUS_FMT_SGBRG10_1X10); - case V4L2_PIX_FMT_SGRBG10: - return (mbus_code == MEDIA_BUS_FMT_SGRBG10_1X10); - case V4L2_PIX_FMT_SRGGB10: - return (mbus_code == MEDIA_BUS_FMT_SRGGB10_1X10); - case V4L2_PIX_FMT_SBGGR12: - return (mbus_code == MEDIA_BUS_FMT_SBGGR12_1X12); - case V4L2_PIX_FMT_SGBRG12: - return (mbus_code == MEDIA_BUS_FMT_SGBRG12_1X12); - case V4L2_PIX_FMT_SGRBG12: - return (mbus_code == MEDIA_BUS_FMT_SGRBG12_1X12); - case V4L2_PIX_FMT_SRGGB12: - return (mbus_code == MEDIA_BUS_FMT_SRGGB12_1X12); - - case V4L2_PIX_FMT_YUYV: - return (mbus_code == MEDIA_BUS_FMT_YUYV8_2X8); - case V4L2_PIX_FMT_YVYU: - return (mbus_code == MEDIA_BUS_FMT_YVYU8_2X8); - case V4L2_PIX_FMT_UYVY: - return (mbus_code == MEDIA_BUS_FMT_UYVY8_2X8); - case V4L2_PIX_FMT_VYUY: - return (mbus_code == MEDIA_BUS_FMT_VYUY8_2X8); - - case V4L2_PIX_FMT_NV12_16L16: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - case V4L2_PIX_FMT_YUV422P: - switch (mbus_code) { - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_VYUY8_2X8: - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_YVYU8_2X8: - return true; - default: - dev_dbg(csi_dev->dev, "Unsupported mbus code: 0x%x\n", - mbus_code); - break; - } - break; - - case V4L2_PIX_FMT_RGB565: - return (mbus_code == MEDIA_BUS_FMT_RGB565_2X8_LE); - case V4L2_PIX_FMT_RGB565X: - return (mbus_code == MEDIA_BUS_FMT_RGB565_2X8_BE); - - case V4L2_PIX_FMT_JPEG: - return (mbus_code == MEDIA_BUS_FMT_JPEG_1X8); - - default: - dev_dbg(csi_dev->dev, "Unsupported pixformat: 0x%x\n", - pixformat); - break; - } - - return false; -} - /* Media */ static const struct media_device_ops sun6i_csi_media_ops = { diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 21932aae3636..941c88920669 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -52,13 +52,4 @@ struct sun6i_csi_variant { unsigned long clk_mod_rate; }; -/** - * sun6i_csi_is_format_supported() - check if the format supported by csi - * @csi: pointer to the csi - * @pixformat: v4l2 pixel format (V4L2_PIX_FMT_*) - * @mbus_code: media bus format code (MEDIA_BUS_FMT_*) - */ -bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev, - u32 pixformat, u32 mbus_code); - #endif /* __SUN6I_CSI_H__ */ diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 91f2295cbdc6..be1a4fe8fe5f 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -1131,63 +1131,81 @@ static const struct v4l2_file_operations sun6i_csi_capture_fops = { /* Media Entity */ -static int -sun6i_csi_capture_link_validate_get_format(struct media_pad *pad, - struct v4l2_subdev_format *fmt) +static int sun6i_csi_capture_link_validate(struct media_link *link) { - if (is_media_entity_v4l2_subdev(pad->entity)) { - struct v4l2_subdev *sd = - media_entity_to_v4l2_subdev(pad->entity); + struct video_device *video_dev = + media_entity_to_video_device(link->sink->entity); + struct sun6i_csi_device *csi_dev = video_get_drvdata(video_dev); + struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; + const struct sun6i_csi_capture_format *capture_format; + const struct sun6i_csi_bridge_format *bridge_format; + unsigned int capture_width, capture_height; + unsigned int bridge_width, bridge_height; + const struct v4l2_format_info *format_info; + u32 pixelformat, capture_field; + u32 mbus_code, bridge_field; + bool match; - fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE; - fmt->pad = pad->index; - return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt); - } + sun6i_csi_capture_dimensions(csi_dev, &capture_width, &capture_height); - return -EINVAL; -} + sun6i_csi_capture_format(csi_dev, &pixelformat, &capture_field); + capture_format = sun6i_csi_capture_format_find(pixelformat); + if (WARN_ON(!capture_format)) + return -EINVAL; -static int sun6i_csi_capture_link_validate(struct media_link *link) -{ - struct video_device *vdev = container_of(link->sink->entity, - struct video_device, entity); - struct sun6i_csi_device *csi_dev = video_get_drvdata(vdev); - struct sun6i_csi_capture *capture = &csi_dev->capture; - struct v4l2_subdev_format source_fmt; - int ret; + sun6i_csi_bridge_dimensions(csi_dev, &bridge_width, &bridge_height); - if (!media_entity_remote_pad(link->sink->entity->pads)) { - dev_info(csi_dev->dev, "capture node %s pad not connected\n", - vdev->name); - return -ENOLINK; + sun6i_csi_bridge_format(csi_dev, &mbus_code, &bridge_field); + bridge_format = sun6i_csi_bridge_format_find(mbus_code); + if (WARN_ON(!bridge_format)) + return -EINVAL; + + /* No cropping/scaling is supported. */ + if (capture_width != bridge_width || capture_height != bridge_height) { + v4l2_err(v4l2_dev, + "invalid input/output dimensions: %ux%u/%ux%u\n", + bridge_width, bridge_height, capture_width, + capture_height); + return -EINVAL; } - ret = sun6i_csi_capture_link_validate_get_format(link->source, - &source_fmt); - if (ret < 0) - return ret; + format_info = v4l2_format_info(pixelformat); + /* Some formats are not listed. */ + if (!format_info) + return 0; + + if (format_info->pixel_enc == V4L2_PIXEL_ENC_BAYER && + bridge_format->input_format != SUN6I_CSI_INPUT_FMT_RAW) + goto invalid; + + if (format_info->pixel_enc == V4L2_PIXEL_ENC_RGB && + bridge_format->input_format != SUN6I_CSI_INPUT_FMT_RAW) + goto invalid; - if (!sun6i_csi_is_format_supported(csi_dev, - capture->format.fmt.pix.pixelformat, - source_fmt.format.code)) { - dev_err(csi_dev->dev, - "Unsupported pixformat: 0x%x with mbus code: 0x%x!\n", - capture->format.fmt.pix.pixelformat, - source_fmt.format.code); - return -EPIPE; + if (format_info->pixel_enc == V4L2_PIXEL_ENC_YUV) { + if (bridge_format->input_format != SUN6I_CSI_INPUT_FMT_YUV420 && + bridge_format->input_format != SUN6I_CSI_INPUT_FMT_YUV422) + goto invalid; + + /* YUV420 input can't produce YUV422 output. */ + if (bridge_format->input_format == SUN6I_CSI_INPUT_FMT_YUV420 && + format_info->vdiv == 1) + goto invalid; } - if (source_fmt.format.width != capture->format.fmt.pix.width || - source_fmt.format.height != capture->format.fmt.pix.height) { - dev_err(csi_dev->dev, - "Wrong width or height %ux%u (%ux%u expected)\n", - capture->format.fmt.pix.width, - capture->format.fmt.pix.height, - source_fmt.format.width, source_fmt.format.height); - return -EPIPE; + /* With raw input mode, we need a 1:1 match between input and output. */ + if (bridge_format->input_format == SUN6I_CSI_INPUT_FMT_RAW || + capture_format->input_format_raw) { + match = sun6i_csi_capture_format_match(pixelformat, mbus_code); + if (!match) + goto invalid; } return 0; + +invalid: + v4l2_err(v4l2_dev, "invalid input/output format combination\n"); + return -EINVAL; } static const struct media_entity_operations sun6i_csi_capture_media_ops = { From patchwork Fri Mar 11 14:35:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778130 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B4C57C433EF for ; Fri, 11 Mar 2022 14:36:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349551AbiCKOh5 (ORCPT ); Fri, 11 Mar 2022 09:37:57 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59728 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349668AbiCKOhw (ORCPT ); Fri, 11 Mar 2022 09:37:52 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AF1721C9B78; Fri, 11 Mar 2022 06:36:43 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 833BB240004; Fri, 11 Mar 2022 14:36:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009401; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ZBGbdEWIKa8ylcY99ku5Po7hP1W07zt3jqCnObrq3TM=; b=eXLXFiBe3lmGuUHJ3aLBzd1ScB+kIZECxr6iG0kJRldFdqh0Zjh5wErgBNcdO0Ah6hcR5H cXS7t9m8pZFLA8r5+FyQJvFFvcD/1jyLBUaLxXURzysb8KW24CYfEddmA7hjeS3lTjJuBA QQyUa1h2GdOFTM9SFqQYwfdbAbK5fsksZM7u51htAy47fBjUj38AGHhHaOs9UKiLqJ6fUC OEJ14nsIglhpPNUL7STRlJnEudm1ju5gH8hAY8mybWRUVmRDOz50K3qQlP+ecUb2lvXM4Y fTodw6m3zGv/+5mt9q5ovhnX/6Pvy1oRX6qNvDN3w4B+Q3Kvn0Eb+7aruEE4ZQ== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 35/46] media: sun6i-csi: Get bridge subdev directly in capture stream ops Date: Fri, 11 Mar 2022 15:35:21 +0100 Message-Id: <20220311143532.265091-36-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org The remote subdev connected to the capture video device is always our bridge, so get the bridge subdev directly instead of using a dedicated helper (which is removed by this commit). Signed-off-by: Paul Kocialkowski --- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 30 ++----------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index be1a4fe8fe5f..2f9bf75e4e39 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -42,22 +42,6 @@ void sun6i_csi_capture_format(struct sun6i_csi_device *csi_dev, *field = csi_dev->capture.format.fmt.pix.field; } -static struct v4l2_subdev * -sun6i_csi_capture_remote_subdev(struct sun6i_csi_capture *capture, u32 *pad) -{ - struct media_pad *remote; - - remote = media_entity_remote_pad(&capture->pad); - - if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) - return NULL; - - if (pad) - *pad = remote->index; - - return media_entity_to_v4l2_subdev(remote->entity); -} - /* Format */ static const struct sun6i_csi_capture_format sun6i_csi_capture_formats[] = { @@ -822,8 +806,8 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, struct sun6i_csi_capture *capture = &csi_dev->capture; struct sun6i_csi_capture_state *state = &capture->state; struct video_device *video_dev = &capture->video_dev; + struct v4l2_subdev *subdev = &csi_dev->bridge.subdev; struct device *dev = csi_dev->dev; - struct v4l2_subdev *subdev; int ret; state->sequence = 0; @@ -832,12 +816,6 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, if (ret < 0) goto error_state; - subdev = sun6i_csi_capture_remote_subdev(capture, NULL); - if (!subdev) { - ret = -EINVAL; - goto error_media_pipeline; - } - /* PM */ ret = pm_runtime_resume_and_get(dev); @@ -886,12 +864,10 @@ static void sun6i_csi_capture_stop_streaming(struct vb2_queue *queue) { struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); struct sun6i_csi_capture *capture = &csi_dev->capture; + struct v4l2_subdev *subdev = &csi_dev->bridge.subdev; struct device *dev = csi_dev->dev; - struct v4l2_subdev *subdev; - subdev = sun6i_csi_capture_remote_subdev(capture, NULL); - if (subdev) - v4l2_subdev_call(subdev, video, s_stream, 0); + v4l2_subdev_call(subdev, video, s_stream, 0); sun6i_csi_capture_disable(csi_dev); sun6i_csi_capture_irq_disable(csi_dev); From patchwork Fri Mar 11 14:35:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778131 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 17D75C433F5 for ; Fri, 11 Mar 2022 14:36:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S245729AbiCKOh5 (ORCPT ); Fri, 11 Mar 2022 09:37:57 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59472 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349683AbiCKOhx (ORCPT ); Fri, 11 Mar 2022 09:37:53 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C1FCC1C9B7F; Fri, 11 Mar 2022 06:36:44 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 1563E24000F; Fri, 11 Mar 2022 14:36:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009403; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=DDdh0lkmEwD/ifsDrXjk6vf+pVzhk63HBeYiMFgPnsE=; b=YZTuhS7drkykHD+YKS4lX/b0WHTfG7IrK25MSL8Hm9LZ3bI24Sbl6A1EF5sJKHXxC7MXYx LEdjPx6paxMW1zdy7BAIzhoKAlRwkY5G+TEf43mZodOwLGe5UVaMukwdHIe4+W+xl0WCUE /2taNH7DzFoy/R5QzaCLIEwZNSRWLAFCuGSIlb4p2Tdu2HnyOE1DtR6EuQujCGhLlVUEHn +GQr4OPj2RwFncAotkL0pzOitFJaQEBqdd9kHjBJHfozFIihJxOm1j9l+pe+/X/BlG7oXB t3p2N/sirRERP/WZdxZ3JTPDIf6DuwdXwKDT/5iVrJ7e2GXdROYzdAKVynjE1w== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 36/46] media: sun6i-csi: Move hardware control to the bridge Date: Fri, 11 Mar 2022 15:35:22 +0100 Message-Id: <20220311143532.265091-37-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org In order to support the isp workflow, we need to be able to configure the hardware from the bridge when the capture device is not used. As a result, move all hardware configuration calls from capture to the bridge. Only the window configuration part (which is specific to using capture) remains there. This effectively opens the way for hooking the bridge to the isp in the future. Signed-off-by: Paul Kocialkowski --- .../sunxi/sun6i-csi/sun6i_csi_bridge.c | 229 ++++++++++++++++ .../sunxi/sun6i-csi/sun6i_csi_capture.c | 249 +----------------- .../sunxi/sun6i-csi/sun6i_csi_capture.h | 3 + 3 files changed, 239 insertions(+), 242 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c index 24a34e1a1dfd..94ed43ba049e 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c @@ -174,11 +174,211 @@ sun6i_csi_bridge_format_find(u32 mbus_code) return NULL; } +/* Bridge */ + +static void sun6i_csi_bridge_irq_enable(struct sun6i_csi_device *csi_dev) +{ + struct regmap *regmap = csi_dev->regmap; + + regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, + SUN6I_CSI_CH_INT_EN_VS | + SUN6I_CSI_CH_INT_EN_HB_OF | + SUN6I_CSI_CH_INT_EN_FIFO2_OF | + SUN6I_CSI_CH_INT_EN_FIFO1_OF | + SUN6I_CSI_CH_INT_EN_FIFO0_OF | + SUN6I_CSI_CH_INT_EN_FD | + SUN6I_CSI_CH_INT_EN_CD); +} + +static void sun6i_csi_bridge_irq_disable(struct sun6i_csi_device *csi_dev) +{ + struct regmap *regmap = csi_dev->regmap; + + regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, 0); +} + +static void sun6i_csi_bridge_irq_clear(struct sun6i_csi_device *csi_dev) +{ + struct regmap *regmap = csi_dev->regmap; + + regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, 0); + regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, + SUN6I_CSI_CH_INT_STA_CLEAR); +} + +static void sun6i_csi_bridge_enable(struct sun6i_csi_device *csi_dev) +{ + struct regmap *regmap = csi_dev->regmap; + + regmap_update_bits(regmap, SUN6I_CSI_EN_REG, SUN6I_CSI_EN_CSI_EN, + SUN6I_CSI_EN_CSI_EN); + + regmap_update_bits(regmap, SUN6I_CSI_CAP_REG, SUN6I_CSI_CAP_VCAP_ON, + SUN6I_CSI_CAP_VCAP_ON); +} + +static void sun6i_csi_bridge_disable(struct sun6i_csi_device *csi_dev) +{ + struct regmap *regmap = csi_dev->regmap; + + regmap_update_bits(regmap, SUN6I_CSI_CAP_REG, SUN6I_CSI_CAP_VCAP_ON, 0); + regmap_update_bits(regmap, SUN6I_CSI_EN_REG, SUN6I_CSI_EN_CSI_EN, 0); +} + +static void +sun6i_csi_bridge_configure_interface(struct sun6i_csi_device *csi_dev) +{ + struct device *dev = csi_dev->dev; + struct regmap *regmap = csi_dev->regmap; + struct v4l2_fwnode_endpoint *endpoint = + &csi_dev->bridge.source->endpoint; + unsigned char bus_width = endpoint->bus.parallel.bus_width; + unsigned int flags = endpoint->bus.parallel.flags; + u32 field; + u32 value = SUN6I_CSI_IF_CFG_IF_CSI; + + sun6i_csi_bridge_format(csi_dev, NULL, &field); + + if (field == V4L2_FIELD_INTERLACED || + field == V4L2_FIELD_INTERLACED_TB || + field == V4L2_FIELD_INTERLACED_BT) + value |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED | + SUN6I_CSI_IF_CFG_FIELD_DT_PCLK_SHIFT(1) | + SUN6I_CSI_IF_CFG_FIELD_DT_FIELD_VSYNC; + else + value |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE; + + switch (endpoint->bus_type) { + case V4L2_MBUS_PARALLEL: + if (bus_width == 16) + value |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_COMBINED; + else + value |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_RAW; + + if (flags & V4L2_MBUS_FIELD_EVEN_LOW) + value |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE; + else + value |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE; + + if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + value |= SUN6I_CSI_IF_CFG_VREF_POL_NEGATIVE; + else + value |= SUN6I_CSI_IF_CFG_VREF_POL_POSITIVE; + + if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + value |= SUN6I_CSI_IF_CFG_HREF_POL_NEGATIVE; + else + value |= SUN6I_CSI_IF_CFG_HREF_POL_POSITIVE; + + if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) + value |= SUN6I_CSI_IF_CFG_CLK_POL_RISING; + else + value |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING; + break; + case V4L2_MBUS_BT656: + if (bus_width == 16) + value |= SUN6I_CSI_IF_CFG_IF_CSI_BT1120; + else + value |= SUN6I_CSI_IF_CFG_IF_CSI_BT656; + + if (flags & V4L2_MBUS_FIELD_EVEN_LOW) + value |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE; + else + value |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE; + + if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) + value |= SUN6I_CSI_IF_CFG_CLK_POL_RISING; + else + value |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING; + break; + default: + dev_warn(dev, "unsupported bus type: %d\n", endpoint->bus_type); + break; + } + + switch (bus_width) { + case 8: + /* 16-bit YUV formats use a doubled width in 8-bit mode. */ + case 16: + value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_8; + break; + case 10: + value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_10; + break; + case 12: + value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_12; + break; + default: + dev_warn(dev, "unsupported bus width: %u\n", bus_width); + break; + } + + regmap_write(regmap, SUN6I_CSI_IF_CFG_REG, value); +} + +static void sun6i_csi_bridge_configure_format(struct sun6i_csi_device *csi_dev) +{ + struct regmap *regmap = csi_dev->regmap; + const struct sun6i_csi_bridge_format *bridge_format; + const struct sun6i_csi_capture_format *capture_format; + u32 mbus_code, field, pixelformat; + u8 input_format, input_yuv_seq, output_format; + u32 value = 0; + + sun6i_csi_bridge_format(csi_dev, &mbus_code, &field); + + bridge_format = sun6i_csi_bridge_format_find(mbus_code); + if (WARN_ON(!bridge_format)) + return; + + input_format = bridge_format->input_format; + input_yuv_seq = bridge_format->input_yuv_seq; + + sun6i_csi_capture_format(csi_dev, &pixelformat, NULL); + + capture_format = sun6i_csi_capture_format_find(pixelformat); + if (WARN_ON(!capture_format)) + return; + + if (capture_format->input_format_raw) + input_format = SUN6I_CSI_INPUT_FMT_RAW; + + if (capture_format->input_yuv_seq_invert) + input_yuv_seq = bridge_format->input_yuv_seq_invert; + + if (field == V4L2_FIELD_INTERLACED || + field == V4L2_FIELD_INTERLACED_TB || + field == V4L2_FIELD_INTERLACED_BT) + output_format = capture_format->output_format_field; + else + output_format = capture_format->output_format_frame; + + value |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(output_format); + value |= SUN6I_CSI_CH_CFG_INPUT_FMT(input_format); + value |= SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(input_yuv_seq); + + if (field == V4L2_FIELD_TOP) + value |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD0; + else if (field == V4L2_FIELD_BOTTOM) + value |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD1; + else + value |= SUN6I_CSI_CH_CFG_FIELD_SEL_EITHER; + + regmap_write(regmap, SUN6I_CSI_CH_CFG_REG, value); +} + +static void sun6i_csi_bridge_configure(struct sun6i_csi_device *csi_dev) +{ + sun6i_csi_bridge_configure_interface(csi_dev); + sun6i_csi_bridge_configure_format(csi_dev); +} + /* V4L2 Subdev */ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on) { struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev); + struct device *dev = csi_dev->dev; struct v4l2_subdev *source_subdev; /* Initialize to 0 to use both in disable label (ret != 0) and off. */ int ret = 0; @@ -195,6 +395,30 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on) goto disable; } + /* PM */ + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + /* Clear */ + + sun6i_csi_bridge_irq_clear(csi_dev); + + /* Configure */ + + sun6i_csi_bridge_configure(csi_dev); + sun6i_csi_capture_configure(csi_dev); + + /* State Update */ + + sun6i_csi_capture_state_update(csi_dev); + + /* Enable */ + + sun6i_csi_bridge_irq_enable(csi_dev); + sun6i_csi_bridge_enable(csi_dev); + ret = v4l2_subdev_call(source_subdev, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) goto disable; @@ -202,8 +426,13 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on) return 0; disable: + sun6i_csi_bridge_irq_disable(csi_dev); + sun6i_csi_bridge_disable(csi_dev); + csi_dev->bridge.source = NULL; + pm_runtime_put(dev); + return ret; } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 2f9bf75e4e39..4315e197d53f 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -6,7 +6,6 @@ */ #include -#include #include #include @@ -330,55 +329,6 @@ static bool sun6i_csi_capture_format_match(u32 pixelformat, u32 mbus_code) /* Capture */ -static void sun6i_csi_capture_irq_enable(struct sun6i_csi_device *csi_dev) -{ - struct regmap *regmap = csi_dev->regmap; - - regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, - SUN6I_CSI_CH_INT_EN_VS | - SUN6I_CSI_CH_INT_EN_HB_OF | - SUN6I_CSI_CH_INT_EN_FIFO2_OF | - SUN6I_CSI_CH_INT_EN_FIFO1_OF | - SUN6I_CSI_CH_INT_EN_FIFO0_OF | - SUN6I_CSI_CH_INT_EN_FD | - SUN6I_CSI_CH_INT_EN_CD); -} - -static void sun6i_csi_capture_irq_disable(struct sun6i_csi_device *csi_dev) -{ - struct regmap *regmap = csi_dev->regmap; - - regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, 0); -} - -static void sun6i_csi_capture_irq_clear(struct sun6i_csi_device *csi_dev) -{ - struct regmap *regmap = csi_dev->regmap; - - regmap_write(regmap, SUN6I_CSI_CH_INT_EN_REG, 0); - regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, - SUN6I_CSI_CH_INT_STA_CLEAR); -} - -static void sun6i_csi_capture_enable(struct sun6i_csi_device *csi_dev) -{ - struct regmap *regmap = csi_dev->regmap; - - regmap_update_bits(regmap, SUN6I_CSI_EN_REG, SUN6I_CSI_EN_CSI_EN, - SUN6I_CSI_EN_CSI_EN); - - regmap_update_bits(regmap, SUN6I_CSI_CAP_REG, SUN6I_CSI_CAP_VCAP_ON, - SUN6I_CSI_CAP_VCAP_ON); -} - -static void sun6i_csi_capture_disable(struct sun6i_csi_device *csi_dev) -{ - struct regmap *regmap = csi_dev->regmap; - - regmap_update_bits(regmap, SUN6I_CSI_CAP_REG, SUN6I_CSI_CAP_VCAP_ON, 0); - regmap_update_bits(regmap, SUN6I_CSI_EN_REG, SUN6I_CSI_EN_CSI_EN, 0); -} - static void sun6i_csi_capture_buffer_configure(struct sun6i_csi_device *csi_dev, struct sun6i_csi_buffer *csi_buffer) @@ -420,148 +370,7 @@ sun6i_csi_capture_buffer_configure(struct sun6i_csi_device *csi_dev, } } -static void -sun6i_csi_capture_configure_interface(struct sun6i_csi_device *csi_dev) -{ - struct device *dev = csi_dev->dev; - struct regmap *regmap = csi_dev->regmap; - struct v4l2_fwnode_endpoint *endpoint = - &csi_dev->bridge.source->endpoint; - unsigned char bus_width = endpoint->bus.parallel.bus_width; - unsigned int flags = endpoint->bus.parallel.flags; - u32 pixelformat, field; - u32 value = SUN6I_CSI_IF_CFG_IF_CSI; - - sun6i_csi_capture_format(csi_dev, &pixelformat, &field); - - if (field == V4L2_FIELD_INTERLACED || - field == V4L2_FIELD_INTERLACED_TB || - field == V4L2_FIELD_INTERLACED_BT) - value |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED | - SUN6I_CSI_IF_CFG_FIELD_DT_PCLK_SHIFT(1) | - SUN6I_CSI_IF_CFG_FIELD_DT_FIELD_VSYNC; - else - value |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE; - - switch (endpoint->bus_type) { - case V4L2_MBUS_PARALLEL: - if (bus_width == 16) - value |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_COMBINED; - else - value |= SUN6I_CSI_IF_CFG_IF_CSI_YUV_RAW; - - if (flags & V4L2_MBUS_FIELD_EVEN_LOW) - value |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE; - else - value |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE; - - if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - value |= SUN6I_CSI_IF_CFG_VREF_POL_NEGATIVE; - else - value |= SUN6I_CSI_IF_CFG_VREF_POL_POSITIVE; - - if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - value |= SUN6I_CSI_IF_CFG_HREF_POL_NEGATIVE; - else - value |= SUN6I_CSI_IF_CFG_HREF_POL_POSITIVE; - - if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) - value |= SUN6I_CSI_IF_CFG_CLK_POL_RISING; - else - value |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING; - break; - case V4L2_MBUS_BT656: - if (bus_width == 16) - value |= SUN6I_CSI_IF_CFG_IF_CSI_BT1120; - else - value |= SUN6I_CSI_IF_CFG_IF_CSI_BT656; - - if (flags & V4L2_MBUS_FIELD_EVEN_LOW) - value |= SUN6I_CSI_IF_CFG_FIELD_NEGATIVE; - else - value |= SUN6I_CSI_IF_CFG_FIELD_POSITIVE; - - if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) - value |= SUN6I_CSI_IF_CFG_CLK_POL_RISING; - else - value |= SUN6I_CSI_IF_CFG_CLK_POL_FALLING; - break; - default: - dev_warn(dev, "unsupported bus type: %d\n", endpoint->bus_type); - break; - } - - switch (bus_width) { - case 8: - /* 16-bit YUV formats use a doubled width in 8-bit mode. */ - case 16: - value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_8; - break; - case 10: - value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_10; - break; - case 12: - value |= SUN6I_CSI_IF_CFG_DATA_WIDTH_12; - break; - default: - dev_warn(dev, "unsupported bus width: %u\n", bus_width); - break; - } - - regmap_write(regmap, SUN6I_CSI_IF_CFG_REG, value); -} - -static void sun6i_csi_capture_configure_format(struct sun6i_csi_device *csi_dev) -{ - struct regmap *regmap = csi_dev->regmap; - const struct sun6i_csi_bridge_format *bridge_format; - const struct sun6i_csi_capture_format *capture_format; - u32 mbus_code, pixelformat, field; - u8 input_format, input_yuv_seq, output_format; - u32 value = 0; - - sun6i_csi_capture_format(csi_dev, &pixelformat, &field); - sun6i_csi_bridge_format(csi_dev, &mbus_code, NULL); - - bridge_format = sun6i_csi_bridge_format_find(mbus_code); - if (WARN_ON(!bridge_format)) - return; - - input_format = bridge_format->input_format; - input_yuv_seq = bridge_format->input_yuv_seq; - - capture_format = sun6i_csi_capture_format_find(pixelformat); - if (WARN_ON(!capture_format)) - return; - - if (capture_format->input_format_raw) - input_format = SUN6I_CSI_INPUT_FMT_RAW; - - if (capture_format->input_yuv_seq_invert) - input_yuv_seq = bridge_format->input_yuv_seq_invert; - - if (field == V4L2_FIELD_INTERLACED || - field == V4L2_FIELD_INTERLACED_TB || - field == V4L2_FIELD_INTERLACED_BT) - output_format = capture_format->output_format_field; - else - output_format = capture_format->output_format_frame; - - value |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(output_format); - value |= SUN6I_CSI_CH_CFG_INPUT_FMT(input_format); - value |= SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(input_yuv_seq); - - if (field == V4L2_FIELD_TOP) - value |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD0; - else if (field == V4L2_FIELD_BOTTOM) - value |= SUN6I_CSI_CH_CFG_FIELD_SEL_FIELD1; - else - value |= SUN6I_CSI_CH_CFG_FIELD_SEL_EITHER; - - regmap_write(regmap, SUN6I_CSI_CH_CFG_REG, value); -} - -static void sun6i_csi_capture_configure_window(struct sun6i_csi_device *csi_dev) +void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev) { struct regmap *regmap = csi_dev->regmap; const struct sun6i_csi_capture_format *format; @@ -624,13 +433,6 @@ static void sun6i_csi_capture_configure_window(struct sun6i_csi_device *csi_dev) SUN6I_CSI_CH_BUF_LEN_LUMA_LINE(luma_line)); } -static void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev) -{ - sun6i_csi_capture_configure_interface(csi_dev); - sun6i_csi_capture_configure_format(csi_dev); - sun6i_csi_capture_configure_window(csi_dev); -} - /* State */ static void sun6i_csi_capture_state_cleanup(struct sun6i_csi_device *csi_dev, @@ -670,7 +472,7 @@ static void sun6i_csi_capture_state_cleanup(struct sun6i_csi_device *csi_dev, spin_unlock_irqrestore(&state->lock, flags); } -static void sun6i_csi_capture_state_update(struct sun6i_csi_device *csi_dev) +void sun6i_csi_capture_state_update(struct sun6i_csi_device *csi_dev) { struct sun6i_csi_capture_state *state = &csi_dev->capture.state; struct sun6i_csi_buffer *csi_buffer; @@ -803,11 +605,9 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, unsigned int count) { struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); - struct sun6i_csi_capture *capture = &csi_dev->capture; - struct sun6i_csi_capture_state *state = &capture->state; - struct video_device *video_dev = &capture->video_dev; + struct sun6i_csi_capture_state *state = &csi_dev->capture.state; + struct video_device *video_dev = &csi_dev->capture.video_dev; struct v4l2_subdev *subdev = &csi_dev->bridge.subdev; - struct device *dev = csi_dev->dev; int ret; state->sequence = 0; @@ -816,41 +616,12 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, if (ret < 0) goto error_state; - /* PM */ - - ret = pm_runtime_resume_and_get(dev); - if (ret < 0) - goto error_media_pipeline; - - /* Clear */ - - sun6i_csi_capture_irq_clear(csi_dev); - - /* Configure */ - - sun6i_csi_capture_configure(csi_dev); - - /* State Update */ - - sun6i_csi_capture_state_update(csi_dev); - - /* Enable */ - - sun6i_csi_capture_irq_enable(csi_dev); - sun6i_csi_capture_enable(csi_dev); - ret = v4l2_subdev_call(subdev, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) - goto error_stream; + goto error_media_pipeline; return 0; -error_stream: - sun6i_csi_capture_disable(csi_dev); - sun6i_csi_capture_irq_disable(csi_dev); - - pm_runtime_put(dev); - error_media_pipeline: media_pipeline_stop(&video_dev->entity); @@ -863,18 +634,12 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, static void sun6i_csi_capture_stop_streaming(struct vb2_queue *queue) { struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); - struct sun6i_csi_capture *capture = &csi_dev->capture; + struct video_device *video_dev = &csi_dev->capture.video_dev; struct v4l2_subdev *subdev = &csi_dev->bridge.subdev; - struct device *dev = csi_dev->dev; v4l2_subdev_call(subdev, video, s_stream, 0); - sun6i_csi_capture_disable(csi_dev); - sun6i_csi_capture_irq_disable(csi_dev); - - pm_runtime_put(dev); - - media_pipeline_stop(&capture->video_dev.entity); + media_pipeline_stop(&video_dev->entity); sun6i_csi_capture_state_cleanup(csi_dev, true); } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h index 2605b16f091c..a61db3bc72e5 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h @@ -63,6 +63,9 @@ void sun6i_csi_capture_format(struct sun6i_csi_device *csi_dev, const struct sun6i_csi_capture_format *sun6i_csi_capture_format_find(u32 pixelformat); +void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev); +void sun6i_csi_capture_state_update(struct sun6i_csi_device *csi_dev); + void sun6i_csi_capture_sync(struct sun6i_csi_device *csi_dev); void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev); From patchwork Fri Mar 11 14:35:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778132 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 32DCDC433F5 for ; Fri, 11 Mar 2022 14:37:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349568AbiCKOh7 (ORCPT ); Fri, 11 Mar 2022 09:37:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59734 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349682AbiCKOhx (ORCPT ); Fri, 11 Mar 2022 09:37:53 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 215491C8DAF; Fri, 11 Mar 2022 06:36:45 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 632AE24000C; Fri, 11 Mar 2022 14:36:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009404; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=LXpRJF0PicFoimO3k7dmVxuvDLPPZZvvYdE5xGjlQ9w=; b=VGYA9Mnqf2UIs8uZLn5qZu9xImvvjKvDQ5dOrl/NvyJ+K8Le4aB5zec4iCB1zxDvDkmaGd mrOeaTrQTBpBxMayaxEplhHpp8LyQCQVOa0Fvfor4JRdnIi3a5t9BybKw/hwCz/iTMmEqb 5OZxXL2A1vVSBpFSLtkqHR2/7oKWXOA8tAmrpAQIzLjmRW20YbmYTAWTjNz05LyLKsWySx a8GTo4DLgjtdTl1ZV0QOpcIzgGjW0M3IpOAVYGe2Fl2lEsyBDdKmqVMKrMIXiqR7VfNAtz ta/bxuzYhTTZ/I2/r35TMPmYLoKU2o5xIEC2FPhtes5aNsvOBP5cqZ2qjulR0A== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 37/46] media: sun6i-csi: Unset bridge source on capture streamon fail Date: Fri, 11 Mar 2022 15:35:23 +0100 Message-Id: <20220311143532.265091-38-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org In cases where the media pipeline start fails but our bridge has already registered a source, the source remains set and the bridge code is not called. Clean it in capture streamon error handler to avoid the issue. Signed-off-by: Paul Kocialkowski --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 4315e197d53f..6033acaa9564 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -628,6 +628,8 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, error_state: sun6i_csi_capture_state_cleanup(csi_dev, false); + csi_dev->bridge.source = NULL; + return ret; } From patchwork Fri Mar 11 14:35:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778141 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 20833C433F5 for ; Fri, 11 Mar 2022 14:37:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349618AbiCKOiO (ORCPT ); Fri, 11 Mar 2022 09:38:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60486 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349555AbiCKOiI (ORCPT ); Fri, 11 Mar 2022 09:38:08 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 16E631C9463; Fri, 11 Mar 2022 06:36:47 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id F3FA924000B; Fri, 11 Mar 2022 14:36:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009406; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/bMGZvUt/JePqe8VlEu0KjPrl5T3acogQy4sy4Jv7Pk=; b=S0RcmxYe36RaOp5pAeZIyeJ3EZAlPXqkVDFQbUGzY4a8rIoxXPY94bIRXmuv8xnpMnW92F 3FsbsA7wX4kTa0nEFPHMGUepGGKCRoZZVgElMQlvCsymFPjZkPx/ABe/qJqMCQC1jH9IFY sAwaVpFbg/CFDZmAJLrNqw75Bixp6a93mPJa6aMKDjzLBXMz8IgLBqq+ryOEBXtXr0Fh06 kN8fVB6Z5OqCiDRLUoAwB7+Bvdk3HzuXmMggjLtG3TD395aWqJaCtaAsFwuNbxW3x/jM/j ELRhE3wiVLfN2r5qBxzXZLXC32CpIluz1r7o6z28QFF886d0wOjd5zIyWVIviw== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 38/46] media: sun6i-csi: Rename the capture video device to sun6i-csi-capture Date: Fri, 11 Mar 2022 15:35:24 +0100 Message-Id: <20220311143532.265091-39-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Now that the driver is properly split between bridge and capture, rename the video device to highlight its role and be in line with the bridge entity naming. Signed-off-by: Paul Kocialkowski --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c | 3 ++- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 6033acaa9564..85ea7812e991 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -1020,7 +1020,8 @@ int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev) /* Video Device */ - strscpy(video_dev->name, SUN6I_CSI_NAME, sizeof(video_dev->name)); + strscpy(video_dev->name, SUN6I_CSI_CAPTURE_NAME, + sizeof(video_dev->name)); video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; video_dev->vfl_dir = VFL_DIR_RX; video_dev->release = video_device_release_empty; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h index a61db3bc72e5..59c57bcefeec 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h @@ -11,6 +11,8 @@ #include #include +#define SUN6I_CSI_CAPTURE_NAME "sun6i-csi-capture" + #define SUN6I_CSI_CAPTURE_WIDTH_MIN 32 #define SUN6I_CSI_CAPTURE_WIDTH_MAX 4800 #define SUN6I_CSI_CAPTURE_HEIGHT_MIN 32 From patchwork Fri Mar 11 14:35:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778149 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2B30EC433EF for ; Fri, 11 Mar 2022 14:37:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1346161AbiCKOiZ (ORCPT ); Fri, 11 Mar 2022 09:38:25 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60508 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349581AbiCKOiI (ORCPT ); Fri, 11 Mar 2022 09:38:08 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 89A5C1C8DBF; Fri, 11 Mar 2022 06:36:49 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id C1C67240006; Fri, 11 Mar 2022 14:36:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009408; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=LT4dHkVvT0HMHJUePD7jqCJHcIh/btKkz6fKkhMkwrM=; b=VEhSRHhI4WbCe1blD7LoPz+gQlW/hbwNlDPhxg7ifWTozyZrjPgClKSsaSMxFkeiCXwXzY 0Ge5M2V/HulAUBnW2LOX+jOZG3Eq5mQpmFhqbrtMOn8yixDevdXWQvtiTI/Vp7RDHYWs8Z XB9Q4fLMXopG9dEmVKxoKua+GwnOcf4pbuzMl/TePyI2m5PaiR66E4H6kI71P1PIe01xgk g79erWBVTKTHFL2pwYxRF34HASgSeSFj3pUtOvIxLKCTuuPzlOSJnRPRUeeT3SYTcuaze3 8PBhsiU+Bpz6FjW4tusO4g/kwi94JDuJLBkSGjfxXbD+7hRh+fRRK2uIC1wmbw== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 39/46] media: sun6i-csi: Cleanup headers and includes, update copyright lines Date: Fri, 11 Mar 2022 15:35:25 +0100 Message-Id: <20220311143532.265091-40-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Cleanup includes, update copyright lines and some cosmetic changes. Signed-off-by: Paul Kocialkowski --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 16 ++++++-------- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 10 ++++----- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 4 ++-- .../sunxi/sun6i-csi/sun6i_csi_capture.h | 22 ++++++++++++++----- .../platform/sunxi/sun6i-csi/sun6i_csi_reg.h | 9 ++++---- 5 files changed, 35 insertions(+), 26 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 298a0c74d12c..19b4f2fe58ff 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -1,18 +1,14 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing) - * All rights reserved. * Author: Yong Deng + * Copyright 2021-2022 Bootlin + * Author: Paul Kocialkowski */ #include -#include -#include #include -#include #include -#include -#include #include #include #include @@ -20,12 +16,13 @@ #include #include #include -#include -#include -#include +#include +#include #include #include "sun6i_csi.h" +#include "sun6i_csi_bridge.h" +#include "sun6i_csi_capture.h" #include "sun6i_csi_reg.h" /* Media */ @@ -407,4 +404,5 @@ module_platform_driver(sun6i_csi_platform_driver); MODULE_DESCRIPTION("Allwinner A31 Camera Sensor Interface driver"); MODULE_AUTHOR("Yong Deng "); +MODULE_AUTHOR("Paul Kocialkowski "); MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 941c88920669..5b267199e407 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -1,16 +1,16 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing) - * All rights reserved. * Author: Yong Deng + * Copyright 2021-2022 Bootlin + * Author: Paul Kocialkowski */ -#ifndef __SUN6I_CSI_H__ -#define __SUN6I_CSI_H__ +#ifndef _SUN6I_CSI_H_ +#define _SUN6I_CSI_H_ #include #include -#include #include #include "sun6i_csi_bridge.h" @@ -52,4 +52,4 @@ struct sun6i_csi_variant { unsigned long clk_mod_rate; }; -#endif /* __SUN6I_CSI_H__ */ +#endif diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 85ea7812e991..67863642df44 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -1,13 +1,13 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing) - * All rights reserved. * Author: Yong Deng + * Copyright 2021-2022 Bootlin + * Author: Paul Kocialkowski */ #include #include - #include #include #include diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h index 59c57bcefeec..ceceb030aef6 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h @@ -1,15 +1,15 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing) - * All rights reserved. * Author: Yong Deng + * Copyright 2021-2022 Bootlin + * Author: Paul Kocialkowski */ -#ifndef __SUN6I_CAPTURE_H__ -#define __SUN6I_CAPTURE_H__ +#ifndef _SUN6I_CAPTURE_H_ +#define _SUN6I_CAPTURE_H_ -#include -#include +#include #define SUN6I_CSI_CAPTURE_NAME "sun6i-csi-capture" @@ -57,21 +57,31 @@ struct sun6i_csi_capture { struct v4l2_format format; }; +/* Helpers */ + void sun6i_csi_capture_dimensions(struct sun6i_csi_device *csi_dev, unsigned int *width, unsigned int *height); void sun6i_csi_capture_format(struct sun6i_csi_device *csi_dev, u32 *pixelformat, u32 *field); +/* Format */ + const struct sun6i_csi_capture_format *sun6i_csi_capture_format_find(u32 pixelformat); +/* Capture */ + void sun6i_csi_capture_configure(struct sun6i_csi_device *csi_dev); void sun6i_csi_capture_state_update(struct sun6i_csi_device *csi_dev); +/* State */ + void sun6i_csi_capture_sync(struct sun6i_csi_device *csi_dev); void sun6i_csi_capture_frame_done(struct sun6i_csi_device *csi_dev); +/* Capture */ + int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev); void sun6i_csi_capture_cleanup(struct sun6i_csi_device *csi_dev); -#endif /* __SUN6I_CAPTURE_H__ */ +#endif diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h index 1e4a07f26d1d..e01c5b9c2d60 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_reg.h @@ -1,12 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing) - * All rights reserved. * Author: Yong Deng + * Copyright 2021-2022 Bootlin + * Author: Paul Kocialkowski */ -#ifndef __SUN6I_CSI_REG_H__ -#define __SUN6I_CSI_REG_H__ +#ifndef _SUN6I_CSI_REG_H_ +#define _SUN6I_CSI_REG_H_ #include @@ -180,4 +181,4 @@ #define SUN6I_CSI_CH_FIFO_STAT_REG 0x98 #define SUN6I_CSI_CH_PCLK_STAT_REG 0x9c -#endif /* __SUN6I_CSI_REG_H__ */ +#endif From patchwork Fri Mar 11 14:35:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778148 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CA0D3C433F5 for ; Fri, 11 Mar 2022 14:37:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234060AbiCKOiY (ORCPT ); Fri, 11 Mar 2022 09:38:24 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60504 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349536AbiCKOiI (ORCPT ); Fri, 11 Mar 2022 09:38:08 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9A0141C8DAF; Fri, 11 Mar 2022 06:36:51 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 45EAA240013; Fri, 11 Mar 2022 14:36:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009410; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=LNXDAhFpBikGWHfUfIWJoLHvqNqjyMVd1qfdpBUFdEU=; b=MRLlFlVSTGgYRIjBThr7JDHVQzGzLgVV7E5M+B4pc4KsJvetj8JHCSSy7xYIfu86l/BY8/ 8sqVZLhaFOTGZriku+UmAKtXQ1XdYkU/zpQjx3qKGa5k4ImH6JnL7OhjWw3X0LHYY6MOS6 9m4SbrsW7471a8P9zmhgSEa9KKjwo8LPeIlCDK/Cb4mcfWLdfPX+AAuKGSe+LffN/djMSS AK+ObQFp83wZ4SKFCCaOu1TXuJanSL8Ta8qU47VE0DbG1f+AfKfLA4WfecWhyw2pezw+fp t1espT7pZ14OM0XJvpzg6YZINCO+TF/QdAfHNJzCaFmVFc2zVpewP//wMeX3Ag== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 40/46] media: sun6i-csi: Add support for MIPI CSI-2 to the bridge code Date: Fri, 11 Mar 2022 15:35:26 +0100 Message-Id: <20220311143532.265091-41-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Introduce MIPI CSI-2 support to the bridge with a new port, source and hardware configuration helper. Signed-off-by: Paul Kocialkowski --- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 1 + .../sunxi/sun6i-csi/sun6i_csi_bridge.c | 34 +++++++++++++++++-- .../sunxi/sun6i-csi/sun6i_csi_bridge.h | 1 + 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 5b267199e407..e3c1150d99f5 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -21,6 +21,7 @@ enum sun6i_csi_port { SUN6I_CSI_PORT_PARALLEL = 0, + SUN6I_CSI_PORT_MIPI_CSI2 = 1, }; struct sun6i_csi_buffer { diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c index 94ed43ba049e..7675333f18dd 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c @@ -226,7 +226,7 @@ static void sun6i_csi_bridge_disable(struct sun6i_csi_device *csi_dev) } static void -sun6i_csi_bridge_configure_interface(struct sun6i_csi_device *csi_dev) +sun6i_csi_bridge_configure_parallel(struct sun6i_csi_device *csi_dev) { struct device *dev = csi_dev->dev; struct regmap *regmap = csi_dev->regmap; @@ -316,6 +316,25 @@ sun6i_csi_bridge_configure_interface(struct sun6i_csi_device *csi_dev) regmap_write(regmap, SUN6I_CSI_IF_CFG_REG, value); } +static void +sun6i_csi_bridge_configure_mipi_csi2(struct sun6i_csi_device *csi_dev) +{ + struct regmap *regmap = csi_dev->regmap; + u32 value = SUN6I_CSI_IF_CFG_IF_MIPI; + u32 field; + + sun6i_csi_bridge_format(csi_dev, NULL, &field); + + if (field == V4L2_FIELD_INTERLACED || + field == V4L2_FIELD_INTERLACED_TB || + field == V4L2_FIELD_INTERLACED_BT) + value |= SUN6I_CSI_IF_CFG_SRC_TYPE_INTERLACED; + else + value |= SUN6I_CSI_IF_CFG_SRC_TYPE_PROGRESSIVE; + + regmap_write(regmap, SUN6I_CSI_IF_CFG_REG, value); +} + static void sun6i_csi_bridge_configure_format(struct sun6i_csi_device *csi_dev) { struct regmap *regmap = csi_dev->regmap; @@ -369,7 +388,11 @@ static void sun6i_csi_bridge_configure_format(struct sun6i_csi_device *csi_dev) static void sun6i_csi_bridge_configure(struct sun6i_csi_device *csi_dev) { - sun6i_csi_bridge_configure_interface(csi_dev); + if (csi_dev->bridge.source == &csi_dev->bridge.source_parallel) + sun6i_csi_bridge_configure_parallel(csi_dev); + else if (csi_dev->bridge.source == &csi_dev->bridge.source_mipi_csi2) + sun6i_csi_bridge_configure_mipi_csi2(csi_dev); + sun6i_csi_bridge_configure_format(csi_dev); } @@ -568,6 +591,8 @@ static int sun6i_csi_bridge_link_validate(struct media_link *link) if (source_subdev == bridge->source_parallel.subdev) bridge->source = &bridge->source_parallel; + else if (source_subdev == bridge->source_mipi_csi2.subdev) + bridge->source = &bridge->source_mipi_csi2; return 0; } @@ -637,6 +662,9 @@ sun6i_csi_bridge_notifier_bound(struct v4l2_async_notifier *notifier, case SUN6I_CSI_PORT_PARALLEL: enabled = true; break; + case SUN6I_CSI_PORT_MIPI_CSI2: + enabled = !bridge->source_parallel.expected; + break; default: break; } @@ -783,6 +811,8 @@ int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev) sun6i_csi_bridge_source_setup(csi_dev, &bridge->source_parallel, SUN6I_CSI_PORT_PARALLEL, parallel_mbus_types); + sun6i_csi_bridge_source_setup(csi_dev, &bridge->source_mipi_csi2, + SUN6I_CSI_PORT_MIPI_CSI2, NULL); ret = v4l2_async_nf_register(v4l2_dev, notifier); if (ret) { diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h index 66fe7942b191..dc30b1509b38 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h @@ -46,6 +46,7 @@ struct sun6i_csi_bridge { struct mutex lock; /* Mbus format lock. */ struct sun6i_csi_bridge_source source_parallel; + struct sun6i_csi_bridge_source source_mipi_csi2; struct sun6i_csi_bridge_source *source; }; From patchwork Fri Mar 11 14:35:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778146 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3D2F2C433EF for ; Fri, 11 Mar 2022 14:37:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349598AbiCKOiW (ORCPT ); Fri, 11 Mar 2022 09:38:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60520 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349602AbiCKOiI (ORCPT ); Fri, 11 Mar 2022 09:38:08 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B34081C9471; Fri, 11 Mar 2022 06:36:53 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id A32B8240012; Fri, 11 Mar 2022 14:36:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009412; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6TiKBCmGO43Q7XNrRJgMew9Bpoke82Sjtw0Mx+U8ARE=; b=ajdoY6RtrbdRLxYku3Qp2G8nkCwho9uAjplE9lqWZmKBd9Y0NjIZbIiRuTImt5lQdAkjmb 88Bg6XuQcUUZSqZtUhs33jzMLCDS+NwV0jitRtP+bG0kJ86DjFXI4gWIgN2Dlr6JuA9cO4 3SS5n1lXvVSl81573fea/eLqSiTa+ppS0QjNGIHGneLREZQcfnbO/FpXzXdpmtdhplfVH+ /wobVv2gTalJOIxWBN7kc4g2X89OgxQ9teRYVSFnyEn5/zG3A3HlDALQKV0cmdOKxZZrlF D/AnhzOxviTBgOdDKKI9DQ/9p8HRtKXO8bUFsZW72tDqOzNYSg/kmOzD4Yt5YA== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 41/46] media: sun6i-csi: Only configure capture when streaming Date: Fri, 11 Mar 2022 15:35:27 +0100 Message-Id: <20220311143532.265091-42-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Add a streaming element to the capture state structure to know if the capture device is used or not. Only configure things related to output when streaming, including the output format, irq, state (dma buffer) and window configuration registers. After this change, it becomes possible to use the bridge without the capture device, which will be the case in the isp media flow. Signed-off-by: Paul Kocialkowski --- .../sunxi/sun6i-csi/sun6i_csi_bridge.c | 50 ++++++++++++------- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 11 +++- .../sunxi/sun6i-csi/sun6i_csi_capture.h | 1 + 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c index 7675333f18dd..ca87ba4c0b9d 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c @@ -338,6 +338,7 @@ sun6i_csi_bridge_configure_mipi_csi2(struct sun6i_csi_device *csi_dev) static void sun6i_csi_bridge_configure_format(struct sun6i_csi_device *csi_dev) { struct regmap *regmap = csi_dev->regmap; + bool capture_streaming = csi_dev->capture.state.streaming; const struct sun6i_csi_bridge_format *bridge_format; const struct sun6i_csi_capture_format *capture_format; u32 mbus_code, field, pixelformat; @@ -353,26 +354,29 @@ static void sun6i_csi_bridge_configure_format(struct sun6i_csi_device *csi_dev) input_format = bridge_format->input_format; input_yuv_seq = bridge_format->input_yuv_seq; - sun6i_csi_capture_format(csi_dev, &pixelformat, NULL); + if (capture_streaming) { + sun6i_csi_capture_format(csi_dev, &pixelformat, NULL); - capture_format = sun6i_csi_capture_format_find(pixelformat); - if (WARN_ON(!capture_format)) - return; + capture_format = sun6i_csi_capture_format_find(pixelformat); + if (WARN_ON(!capture_format)) + return; - if (capture_format->input_format_raw) - input_format = SUN6I_CSI_INPUT_FMT_RAW; + if (capture_format->input_format_raw) + input_format = SUN6I_CSI_INPUT_FMT_RAW; - if (capture_format->input_yuv_seq_invert) - input_yuv_seq = bridge_format->input_yuv_seq_invert; + if (capture_format->input_yuv_seq_invert) + input_yuv_seq = bridge_format->input_yuv_seq_invert; - if (field == V4L2_FIELD_INTERLACED || - field == V4L2_FIELD_INTERLACED_TB || - field == V4L2_FIELD_INTERLACED_BT) - output_format = capture_format->output_format_field; - else - output_format = capture_format->output_format_frame; + if (field == V4L2_FIELD_INTERLACED || + field == V4L2_FIELD_INTERLACED_TB || + field == V4L2_FIELD_INTERLACED_BT) + output_format = capture_format->output_format_field; + else + output_format = capture_format->output_format_frame; + + value |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(output_format); + } - value |= SUN6I_CSI_CH_CFG_OUTPUT_FMT(output_format); value |= SUN6I_CSI_CH_CFG_INPUT_FMT(input_format); value |= SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(input_yuv_seq); @@ -401,6 +405,7 @@ static void sun6i_csi_bridge_configure(struct sun6i_csi_device *csi_dev) static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on) { struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev); + bool capture_streaming = csi_dev->capture.state.streaming; struct device *dev = csi_dev->dev; struct v4l2_subdev *source_subdev; /* Initialize to 0 to use both in disable label (ret != 0) and off. */ @@ -431,15 +436,20 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on) /* Configure */ sun6i_csi_bridge_configure(csi_dev); - sun6i_csi_capture_configure(csi_dev); + + if (capture_streaming) + sun6i_csi_capture_configure(csi_dev); /* State Update */ - sun6i_csi_capture_state_update(csi_dev); + if (capture_streaming) + sun6i_csi_capture_state_update(csi_dev); /* Enable */ - sun6i_csi_bridge_irq_enable(csi_dev); + if (capture_streaming) + sun6i_csi_bridge_irq_enable(csi_dev); + sun6i_csi_bridge_enable(csi_dev); ret = v4l2_subdev_call(source_subdev, video, s_stream, 1); @@ -449,7 +459,9 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on) return 0; disable: - sun6i_csi_bridge_irq_disable(csi_dev); + if (capture_streaming) + sun6i_csi_bridge_irq_disable(csi_dev); + sun6i_csi_bridge_disable(csi_dev); csi_dev->bridge.source = NULL; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index 67863642df44..f6dac15af675 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -616,13 +616,17 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, if (ret < 0) goto error_state; + state->streaming = true; + ret = v4l2_subdev_call(subdev, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) - goto error_media_pipeline; + goto error_streaming; return 0; -error_media_pipeline: +error_streaming: + state->streaming = false; + media_pipeline_stop(&video_dev->entity); error_state: @@ -636,11 +640,14 @@ static int sun6i_csi_capture_start_streaming(struct vb2_queue *queue, static void sun6i_csi_capture_stop_streaming(struct vb2_queue *queue) { struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); + struct sun6i_csi_capture_state *state = &csi_dev->capture.state; struct video_device *video_dev = &csi_dev->capture.video_dev; struct v4l2_subdev *subdev = &csi_dev->bridge.subdev; v4l2_subdev_call(subdev, video, s_stream, 0); + state->streaming = false; + media_pipeline_stop(&video_dev->entity); sun6i_csi_capture_state_cleanup(csi_dev, true); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h index ceceb030aef6..29893cf96f6b 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h @@ -44,6 +44,7 @@ struct sun6i_csi_capture_state { struct sun6i_csi_buffer *complete; unsigned int sequence; + bool streaming; }; struct sun6i_csi_capture { From patchwork Fri Mar 11 14:35:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778147 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4F1CDC433FE for ; Fri, 11 Mar 2022 14:37:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349621AbiCKOiX (ORCPT ); Fri, 11 Mar 2022 09:38:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60518 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349601AbiCKOiI (ORCPT ); Fri, 11 Mar 2022 09:38:08 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5E0B11C9472; Fri, 11 Mar 2022 06:36:54 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 75385240008; Fri, 11 Mar 2022 14:36:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009413; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Xswwx9naACSRayy5J2yvzI10IWOb2cFHob9k2G9cPIo=; b=jvFRD/OyMrB/P2RaiH1rf8nVEXZOA4RIZeSnHGQzVLv9PH+XcMDoSvYzFAK/sR2pSJKmQN 2J3A43En8u10TzyXnWPr7BhBq08jEbSKkf7/eyBR4VPxnR/WXt9zq8tfdM8DhcRlFQK+7D i9L3YgaGf1Yi/QTlKuK18N7jy2krzbUuuLoKZQ8BKC8Gemk76JRriLpqqHtx9CukPl1qYv GnPytbupYg6B3ZuLS3v0gaITa+FSvzz+VPnN+yRwFBwAPAXySL3483Sf4eoxoJcua9V7oX S4VDbSgr4hK39Yy8I9ZCSrDS/WQL4R6N/Q0/wwzb+eKo87TSdfhORdoJdi1Bxg== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 42/46] media: sun6i-csi: Add extra checks to the interrupt routine Date: Fri, 11 Mar 2022 15:35:28 +0100 Message-Id: <20220311143532.265091-43-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Check against the enabled bits and make sure capture is running before serving an interrupt, to add extra safety in the process. Signed-off-by: Paul Kocialkowski --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 19b4f2fe58ff..b28e5eaf4622 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -105,13 +105,17 @@ static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev) static irqreturn_t sun6i_csi_isr(int irq, void *private) { struct sun6i_csi_device *csi_dev = private; + bool capture_streaming = csi_dev->capture.state.streaming; struct regmap *regmap = csi_dev->regmap; - u32 status; + u32 status = 0, enable = 0; regmap_read(regmap, SUN6I_CSI_CH_INT_STA_REG, &status); + regmap_read(regmap, SUN6I_CSI_CH_INT_EN_REG, &enable); - if (!(status & 0xFF)) + if (!status) return IRQ_NONE; + else if (!(status & enable) || !capture_streaming) + goto complete; if ((status & SUN6I_CSI_CH_INT_STA_FIFO0_OF) || (status & SUN6I_CSI_CH_INT_STA_FIFO1_OF) || @@ -132,6 +136,7 @@ static irqreturn_t sun6i_csi_isr(int irq, void *private) if (status & SUN6I_CSI_CH_INT_STA_VS) sun6i_csi_capture_sync(csi_dev); +complete: regmap_write(regmap, SUN6I_CSI_CH_INT_STA_REG, status); return IRQ_HANDLED; From patchwork Fri Mar 11 14:35:29 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778150 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1A721C433EF for ; Fri, 11 Mar 2022 14:37:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242005AbiCKOij (ORCPT ); Fri, 11 Mar 2022 09:38:39 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60570 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349615AbiCKOiJ (ORCPT ); Fri, 11 Mar 2022 09:38:09 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 455DF1C947A; Fri, 11 Mar 2022 06:36:57 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id E0FA1240011; Fri, 11 Mar 2022 14:36:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009415; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=gPtNVTUd4yP1lJocgKUeubQb7IU5L3ybRm3zk/OadgA=; b=Vud4ZHvg0Uo9MSqeKnIXCCvM3rygEXRb0rwt9dHBgYBMZDM701SVzeXf+xNVX6yDur7fxM qyffJHDzMlskaE49o73SRAqtwam/ttNKZS92Y124XqwrpjxpQgs1cYZ8jcHoD/KU/ggFGX kxKmmCDcBGLWjhjivEuwbN03ArVgvArQGPyUKvAK9gKF0TrinB9ofrapjILvFgFZ/ObVNb ex4+beUKbKc/m9WwAKPSySEBgGag55z84dLwQBMaHmleTmYapWTYzTxtiJWnvJM6h9KWQh nhpQUt74OUgACI84C1F/dQ+/X5PgUggr4dsScIMgpJIWTVsukj4/pCpkFZTq4Q== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 43/46] media: sun6i-csi: Request a shared interrupt Date: Fri, 11 Mar 2022 15:35:29 +0100 Message-Id: <20220311143532.265091-44-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Request our interrupt shared since it is typically shared with the isp block. The interrupt routine looks good to go for shared irq. Signed-off-by: Paul Kocialkowski --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index b28e5eaf4622..794ac53dcd30 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -280,8 +280,8 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, goto error_clk_rate_exclusive; } - ret = devm_request_irq(dev, irq, sun6i_csi_isr, 0, SUN6I_CSI_NAME, - csi_dev); + ret = devm_request_irq(dev, irq, sun6i_csi_isr, IRQF_SHARED, + SUN6I_CSI_NAME, csi_dev); if (ret) { dev_err(dev, "failed to request interrupt\n"); goto error_clk_rate_exclusive; From patchwork Fri Mar 11 14:35:30 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778153 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A8402C433FE for ; Fri, 11 Mar 2022 14:37:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349599AbiCKOi7 (ORCPT ); Fri, 11 Mar 2022 09:38:59 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60506 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349662AbiCKOiQ (ORCPT ); Fri, 11 Mar 2022 09:38:16 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 359F51C9B54; Fri, 11 Mar 2022 06:36:59 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id E1903240007; Fri, 11 Mar 2022 14:36:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009417; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=zDmhoLPQge3kG9Ojz9okiMcdcrF7ESNnFjv2vshc9E8=; b=CkMzxPXpS0SWFrfc4VdTua2320ouiDSqKn/9yyYp6rGxR7K0hB/pMeRX7rdXv1BAevuoos oWRRaT9ddbaafbH5auuO1jplMG+OmZBdVTkd82bR0hyM0+VbLJUKAxK8kOBuOfvseEmQOf W2LJwZ5Wchg2hId7VjvL2w1UQZYQ1n1H61ZAs3dsLLwio2GZWX6tk7grSc0vpptjUgR3LA 21pW3BexthWMrW3JlgGSBfvhbdXzCU0k76JF07QJgnFpOADVmRfR2+rs1k+FvbwtPPVcSu kKfGt6upmoe/AIC4PQeLN6szH33+4MqVuTzUWtjvzB3IjwphJb3DOhr8J6LYNQ== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 44/46] media: sun6i-csi: Detect the availability of the ISP Date: Fri, 11 Mar 2022 15:35:30 +0100 Message-Id: <20220311143532.265091-45-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Add a helper to detect whether the ISP is available and connected and store the indication in a driver-wide variable. Signed-off-by: Paul Kocialkowski --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 33 +++++++++++++++++++ .../platform/sunxi/sun6i-csi/sun6i_csi.h | 3 ++ 2 files changed, 36 insertions(+) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 794ac53dcd30..f17be8e091a9 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -25,6 +25,35 @@ #include "sun6i_csi_capture.h" #include "sun6i_csi_reg.h" +/* ISP */ + +static bool sun6i_csi_isp_detect(struct sun6i_csi_device *csi_dev) +{ + struct device *dev = csi_dev->dev; + struct fwnode_handle *handle = NULL; + + /* ISP is not available if disabled in kernel config. */ + if (!IS_ENABLED(CONFIG_VIDEO_SUN6I_ISP)) + return 0; + + /* + * ISP is not available if not connected via fwnode graph. + * This weill also check that the remote parent node is available. + */ + handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), + SUN6I_CSI_PORT_ISP, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + if (!handle) + return 0; + + fwnode_handle_put(handle); + + dev_info(dev, "ISP link is available\n"); + csi_dev->isp_available = true; + + return 0; +} + /* Media */ static const struct media_device_ops sun6i_csi_media_ops = { @@ -323,6 +352,10 @@ static int sun6i_csi_probe(struct platform_device *platform_dev) if (ret) return ret; + ret = sun6i_csi_isp_detect(csi_dev); + if (ret) + goto error_resources; + ret = sun6i_csi_v4l2_setup(csi_dev); if (ret) goto error_resources; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index e3c1150d99f5..ee5b04f75311 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -22,6 +22,7 @@ enum sun6i_csi_port { SUN6I_CSI_PORT_PARALLEL = 0, SUN6I_CSI_PORT_MIPI_CSI2 = 1, + SUN6I_CSI_PORT_ISP = 2, }; struct sun6i_csi_buffer { @@ -47,6 +48,8 @@ struct sun6i_csi_device { struct clk *clk_mod; struct clk *clk_ram; struct reset_control *reset; + + bool isp_available; }; struct sun6i_csi_variant { From patchwork Fri Mar 11 14:35:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778151 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C6DBFC433FE for ; Fri, 11 Mar 2022 14:37:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349692AbiCKOil (ORCPT ); Fri, 11 Mar 2022 09:38:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60804 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349689AbiCKOiQ (ORCPT ); Fri, 11 Mar 2022 09:38:16 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::221]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 49CEA1C944F; Fri, 11 Mar 2022 06:37:01 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 1580824001C; Fri, 11 Mar 2022 14:36:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009419; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=JwIiF68nNHAf8x4sv8J+sKaKdAx468YQMtKNaqm7Q/A=; b=P/h7FT7IwE8IIbe6wcBrkhnWkszWu6CJowkm6aG9G49cmLk9LW/g96xUOpFWtY+RW+MRzJ 9sW0zXJS2E1M3wNKeg4oXqev8Ub84ypwno+/FlPT9dFVLP4nuRI7yojOUGMjZ+vPAiec9p uEmjdakB2/ere3DfMdPuWnAZ6ukTHGJu+Wer+sc69iAiP0ext5YPWIS4I6OiWbEpI8PpOT YAF02kthEx5LH0L3dyIzVKCbWOUYuovmXHotyoiMcWSVrDWA8mxOOim2Z/8RMc4dhslq2Q glFu4uzJY6fOm8I2x2vHuffo8Fb7WHN7oG8EpdTwWV/qW2NT7xkDSZR8zrNXUg== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 45/46] media: sun6i-csi: Add support for hooking to the isp devices Date: Fri, 11 Mar 2022 15:35:31 +0100 Message-Id: <20220311143532.265091-46-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org In order to use the isp and csi together, both devices need to be parented to the same v4l2 and media devices. We use the isp as top-level device and let the csi code hook to its v4l2 and media devices when async subdev registration takes place. As a result v4l2/media device setup is only called when the ISP is missing and the capture device is registered after the devices are hooked. The bridge subdev and its notifier are registered without any device when the ISP is available. Top-level pointers for the devices are introduced to either redirect to the hooked ones (isp available) or the registered ones (isp missing). Also keep track of whether the capture node was setup or not to avoid cleaning up resources when it wasn't. Signed-off-by: Paul Kocialkowski --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 45 +++++++++++++++---- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 7 +++ .../sunxi/sun6i-csi/sun6i_csi_bridge.c | 31 +++++++++++-- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 19 ++++++-- .../sunxi/sun6i-csi/sun6i_csi_capture.h | 1 + 5 files changed, 88 insertions(+), 15 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index f17be8e091a9..56c8595dfdb1 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -27,6 +27,18 @@ /* ISP */ +int sun6i_csi_isp_complete(struct sun6i_csi_device *csi_dev, + struct v4l2_device *v4l2_dev) +{ + if (csi_dev->v4l2_dev && csi_dev->v4l2_dev != v4l2_dev) + return -EINVAL; + + csi_dev->v4l2_dev = v4l2_dev; + csi_dev->media_dev = v4l2_dev->mdev; + + return sun6i_csi_capture_setup(csi_dev); +} + static bool sun6i_csi_isp_detect(struct sun6i_csi_device *csi_dev) { struct device *dev = csi_dev->dev; @@ -107,6 +119,9 @@ static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) goto error_v4l2_ctrl; } + csi_dev->v4l2_dev = v4l2_dev; + csi_dev->media_dev = media_dev; + return 0; error_v4l2_ctrl: @@ -356,17 +371,27 @@ static int sun6i_csi_probe(struct platform_device *platform_dev) if (ret) goto error_resources; - ret = sun6i_csi_v4l2_setup(csi_dev); - if (ret) - goto error_resources; + /* + * Register our own v4l2 and media devices when there is no ISP around. + * Otherwise the ISP will use async subdev registration with our bridge, + * which will provide v4l2 and media devices that are used to register + * the video interface. + */ + if (!csi_dev->isp_available) { + ret = sun6i_csi_v4l2_setup(csi_dev); + if (ret) + goto error_resources; + } ret = sun6i_csi_bridge_setup(csi_dev); if (ret) goto error_v4l2; - ret = sun6i_csi_capture_setup(csi_dev); - if (ret) - goto error_bridge; + if (!csi_dev->isp_available) { + ret = sun6i_csi_capture_setup(csi_dev); + if (ret) + goto error_bridge; + } return 0; @@ -374,7 +399,8 @@ static int sun6i_csi_probe(struct platform_device *platform_dev) sun6i_csi_bridge_cleanup(csi_dev); error_v4l2: - sun6i_csi_v4l2_cleanup(csi_dev); + if (!csi_dev->isp_available) + sun6i_csi_v4l2_cleanup(csi_dev); error_resources: sun6i_csi_resources_cleanup(csi_dev); @@ -388,7 +414,10 @@ static int sun6i_csi_remove(struct platform_device *pdev) sun6i_csi_capture_cleanup(csi_dev); sun6i_csi_bridge_cleanup(csi_dev); - sun6i_csi_v4l2_cleanup(csi_dev); + + if (!csi_dev->isp_available) + sun6i_csi_v4l2_cleanup(csi_dev); + sun6i_csi_resources_cleanup(csi_dev); return 0; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index ee5b04f75311..ef9405891cc7 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -38,6 +38,8 @@ struct sun6i_csi_v4l2 { struct sun6i_csi_device { struct device *dev; + struct v4l2_device *v4l2_dev; + struct media_device *media_dev; struct sun6i_csi_v4l2 v4l2; struct sun6i_csi_bridge bridge; @@ -56,4 +58,9 @@ struct sun6i_csi_variant { unsigned long clk_mod_rate; }; +/* ISP */ + +int sun6i_csi_isp_complete(struct sun6i_csi_device *csi_dev, + struct v4l2_device *v4l2_dev); + #endif diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c index ca87ba4c0b9d..02bad44f097f 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c @@ -683,6 +683,16 @@ sun6i_csi_bridge_notifier_bound(struct v4l2_async_notifier *notifier, source->subdev = remote_subdev; + if (csi_dev->isp_available) { + /* + * Hook to the first available remote subdev to get v4l2 and + * media devices and register the capture device then. + */ + ret = sun6i_csi_isp_complete(csi_dev, remote_subdev->v4l2_dev); + if (ret) + return ret; + } + return sun6i_csi_bridge_link(csi_dev, SUN6I_CSI_BRIDGE_PAD_SINK, remote_subdev, enabled); } @@ -695,6 +705,9 @@ sun6i_csi_bridge_notifier_complete(struct v4l2_async_notifier *notifier) bridge.notifier); struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; + if (csi_dev->isp_available) + return 0; + return v4l2_device_register_subdev_nodes(v4l2_dev); } @@ -768,7 +781,7 @@ int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev) { struct device *dev = csi_dev->dev; struct sun6i_csi_bridge *bridge = &csi_dev->bridge; - struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; + struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev; struct v4l2_subdev *subdev = &bridge->subdev; struct v4l2_async_notifier *notifier = &bridge->notifier; struct media_pad *pads = bridge->pads; @@ -809,7 +822,11 @@ int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev) /* V4L2 Subdev */ - ret = v4l2_device_register_subdev(v4l2_dev, subdev); + if (csi_dev->isp_available) + ret = v4l2_async_register_subdev(subdev); + else + ret = v4l2_device_register_subdev(v4l2_dev, subdev); + if (ret) { dev_err(dev, "failed to register v4l2 subdev: %d\n", ret); goto error_media_entity; @@ -826,7 +843,10 @@ int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev) sun6i_csi_bridge_source_setup(csi_dev, &bridge->source_mipi_csi2, SUN6I_CSI_PORT_MIPI_CSI2, NULL); - ret = v4l2_async_nf_register(v4l2_dev, notifier); + if (csi_dev->isp_available) + ret = v4l2_async_subdev_nf_register(subdev, notifier); + else + ret = v4l2_async_nf_register(v4l2_dev, notifier); if (ret) { dev_err(dev, "failed to register v4l2 async notifier: %d\n", ret); @@ -838,7 +858,10 @@ int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev) error_v4l2_async_notifier: v4l2_async_nf_cleanup(notifier); - v4l2_device_unregister_subdev(subdev); + if (csi_dev->isp_available) + v4l2_async_unregister_subdev(subdev); + else + v4l2_device_unregister_subdev(subdev); error_media_entity: media_entity_cleanup(&subdev->entity); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index f6dac15af675..2ad38277633f 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -570,7 +570,7 @@ static int sun6i_csi_capture_buffer_prepare(struct vb2_buffer *buffer) { struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue); struct sun6i_csi_capture *capture = &csi_dev->capture; - struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; + struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev; struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer); unsigned long size = capture->format.fmt.pix.sizeimage; @@ -886,7 +886,7 @@ static int sun6i_csi_capture_link_validate(struct media_link *link) struct video_device *video_dev = media_entity_to_video_device(link->sink->entity); struct sun6i_csi_device *csi_dev = video_get_drvdata(video_dev); - struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; + struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev; const struct sun6i_csi_capture_format *capture_format; const struct sun6i_csi_bridge_format *bridge_format; unsigned int capture_width, capture_height; @@ -968,7 +968,7 @@ int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev) { struct sun6i_csi_capture *capture = &csi_dev->capture; struct sun6i_csi_capture_state *state = &capture->state; - struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; + struct v4l2_device *v4l2_dev = csi_dev->v4l2_dev; struct v4l2_subdev *bridge_subdev = &csi_dev->bridge.subdev; struct video_device *video_dev = &capture->video_dev; struct vb2_queue *queue = &capture->queue; @@ -977,6 +977,10 @@ int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev) struct v4l2_pix_format *pix_format = &format->fmt.pix; int ret; + /* This may happen with multiple bridge notifier bound calls. */ + if (state->setup) + return 0; + /* State */ INIT_LIST_HEAD(&state->queue); @@ -1055,6 +1059,7 @@ int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev) ret = media_create_pad_link(&bridge_subdev->entity, SUN6I_CSI_BRIDGE_PAD_SOURCE, &video_dev->entity, 0, + csi_dev->isp_available ? 0 : MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); if (ret < 0) { @@ -1065,6 +1070,8 @@ int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev) goto error_video_device; } + state->setup = true; + return 0; error_video_device: @@ -1083,7 +1090,13 @@ void sun6i_csi_capture_cleanup(struct sun6i_csi_device *csi_dev) struct sun6i_csi_capture *capture = &csi_dev->capture; struct video_device *video_dev = &capture->video_dev; + /* This may happen if async registration failed to complete. */ + if (!capture->state.setup) + return; + vb2_video_unregister_device(video_dev); media_entity_cleanup(&video_dev->entity); mutex_destroy(&capture->lock); + + capture->state.setup = false; } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h index 29893cf96f6b..3ee5ccefbd10 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.h @@ -45,6 +45,7 @@ struct sun6i_csi_capture_state { unsigned int sequence; bool streaming; + bool setup; }; struct sun6i_csi_capture { From patchwork Fri Mar 11 14:35:32 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12778152 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 777CCC433F5 for ; Fri, 11 Mar 2022 14:37:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349695AbiCKOi6 (ORCPT ); Fri, 11 Mar 2022 09:38:58 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60520 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349697AbiCKOiR (ORCPT ); Fri, 11 Mar 2022 09:38:17 -0500 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9A0611CA5C2; Fri, 11 Mar 2022 06:37:02 -0800 (PST) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id F22AD24000C; Fri, 11 Mar 2022 14:36:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1647009421; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=IGe1fBLDVUFuRicfbGDrdMG7UD+cffaBQQk4odYtgqs=; b=UVKwKS07KcPK7PuqRebeYyaVf0xx5W8ON7Kk77bviCSdfC67Fj1zx5Zy5QPJfKjO0mAuBt 5rYaaoEyQ/u+WeMIzlnBUItZeDWnfpSjGfKXKubIxTUEw2NeXPR+7zIFbESIcbY7bLWX8M ydOv9UbCYH7vb8Xr5MsslVb5rqT724C4PfuYK3K/BzwYcnw5a/6M3SHfbdSm/dYs1ptWR+ dKsRq0GsnqlrjaTcU1Bi4P0txcMri1jyqW5vRYP3ZdBDhemIoKz/+KCLqqSUVjql9oi3Qb UzfBMWVPvqVrjrJSUHGTksvbpfHwxfMqQKbosJ2KOVxwfKc1mEbObND9bKuOvQ== From: Paul Kocialkowski To: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Cc: Yong Deng , Paul Kocialkowski , Mauro Carvalho Chehab , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland , Laurent Pinchart , Maxime Ripard , Thomas Petazzoni Subject: [PATCH v3 46/46] MAINTAINERS: Add myself as sun6i-csi maintainer and rename/move entry Date: Fri, 11 Mar 2022 15:35:32 +0100 Message-Id: <20220311143532.265091-47-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> References: <20220311143532.265091-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Given the substantial rework of the driver that I carried out and the knowledge acquired about the hardware along the way, make myself a maintainer of the sun6i-csi driver. Also rename and move the entry while at it since the driver is not specific to the V3s. Signed-off-by: Paul Kocialkowski --- MAINTAINERS | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index ed1758d194a5..164e1b57337f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -752,6 +752,15 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml F: drivers/media/platform/sunxi/sun4i-csi/ +ALLWINNER A31 CSI DRIVER +M: Yong Deng +M: Paul Kocialkowski +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml +F: drivers/media/platform/sunxi/sun6i-csi/ + ALLWINNER A31 MIPI CSI-2 BRIDGE DRIVER M: Paul Kocialkowski L: linux-media@vger.kernel.org @@ -5115,14 +5124,6 @@ M: Jaya Kumar S: Maintained F: sound/pci/cs5535audio/ -CSI DRIVERS FOR ALLWINNER V3s -M: Yong Deng -L: linux-media@vger.kernel.org -S: Maintained -T: git git://linuxtv.org/media_tree.git -F: Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml -F: drivers/media/platform/sunxi/sun6i-csi/ - CW1200 WLAN driver M: Solomon Peachy S: Maintained