From patchwork Fri Apr 15 15:27: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: 12815032 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 8C702C433FE for ; Fri, 15 Apr 2022 15:28:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355032AbiDOPax (ORCPT ); Fri, 15 Apr 2022 11:30:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37434 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348962AbiDOPav (ORCPT ); Fri, 15 Apr 2022 11:30:51 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1D490D3AE6; Fri, 15 Apr 2022 08:28:21 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 50290E0009; Fri, 15 Apr 2022 15:28:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036500; 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=CEm5+pGRNel/0Old7UzJMKf1s19Es9J+Jjzr7jKNOZ0=; b=X2CQrLsOEU929UKZI3UjKfC+rGr76kJN1MWbcUik/HnoE3rzeJljFY6o96WZHpshvPTuek zZh61Sh5Q6xCG12k59ZCc6Gyl1B7yDYIwL4Qqx5kR5htr7ZuGw7YB7Rp4AfA9rEei9VOhM sUJ2+NIiZbeZ5FkXuqTUGfq76H3+7OaIsJe0zzU0sAxbJtolKlPloTIaQ7MiWU+Ilij+20 jctsp3eW3BS7L1H+8nPQWY78gNtF2sxYV5fbU3URP+bYqRsWOE3I6HXHA9kg0g+lvNAC+t MBC+bYfGOMNA30+ED+SkXvX5oUbbmYEbiRGVaujNMoIEgrhDmPGKKXVk318Vlw== 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 v4 01/45] media: sun6i-csi: Define and use driver name and (reworked) description Date: Fri, 15 Apr 2022 17:27:27 +0200 Message-Id: <20220415152811.636419-2-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Apr 15 15:27: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: 12815035 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 A82F4C433FE for ; Fri, 15 Apr 2022 15:28:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355100AbiDOPa6 (ORCPT ); Fri, 15 Apr 2022 11:30:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37476 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355050AbiDOPay (ORCPT ); Fri, 15 Apr 2022 11:30:54 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 803D3D3AF4; Fri, 15 Apr 2022 08:28:23 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 85C8EE0005; Fri, 15 Apr 2022 15:28:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036501; 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=1qqTXyOEeXjhc8P976CFgKGyed4EBwdT6bRBBFhzza0=; b=Jjb4w5ooRKyiWaGHCi0FDblZcZq8iZ/D/dz15dE3vdfG8wHIUaBvdMZyixgiYjkCP9cVB2 QOoUxrANf7gwXFeh9HcYwdA7bk4zcKKwpkksJ6P7i8T5tw0vM3tWQPYWIeDTY9uzOiI6x4 QvRVY0Tmd64NUvE9SR2tZIzY53i38wEuJcBOuSNeUY+poTxWLjNAL4cRGs/1F0pIz2MmFa Yz8bb1j5W7QWfW03JOnIb5gJqiJDYrVlgsp5CKjvwK5umZjQRG9lgIyfkIUvBjqJi1jebY 4BMbtRSYD9a0rFmyKkewUb68SxTG34nCVxil5sL6mNonmxcV0Wwd+k79xYTXAQ== 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 v4 02/45] media: sun6i-csi: Refactor main driver data structures Date: Fri, 15 Apr 2022 17:27:28 +0200 Message-Id: <20220415152811.636419-3-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 682c26536034..314b56ca5b33 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; } @@ -488,7 +488,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; @@ -516,7 +516,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); @@ -561,7 +561,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; } @@ -570,10 +570,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); @@ -582,7 +582,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); @@ -598,15 +598,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; @@ -641,11 +642,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; } @@ -656,7 +658,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; @@ -664,7 +666,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 Apr 15 15:27: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: 12815034 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 CE380C433EF for ; Fri, 15 Apr 2022 15:28:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355112AbiDOPa7 (ORCPT ); Fri, 15 Apr 2022 11:30:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37460 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229850AbiDOPax (ORCPT ); Fri, 15 Apr 2022 11:30:53 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 76952D3AE5; Fri, 15 Apr 2022 08:28:24 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id DFC26E0007; Fri, 15 Apr 2022 15:28:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036502; 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=Kf/LiFt2w5n6LAhs+x9ONo9acw4Kl67ZgsV7GIopoh0=; b=lYjWu6z50aWKbrA4wnh9x9n/aSsl/xKGq0SDfXJ42sa2IagcfqxcmXSX/hrlG+fwOaavNP CUlhoyHx9uDCC9ak3Uen8detp6Q80w3su4we0xlZ5XQZPmsBEe/Lg5G4IXqShYOI54pyW9 wc/ogreMqWBFAluDl91WwIl04ckD9yNzwV/Rv0w7SRtmGJ5kAFiakbhuiK8InfrdhrIZfY JIVNr0VME2nhjPneJfputiHwZCcmZ0xo0QosyEGZUPruOkru1aBjiEXdlcRPBIqJtrFJ64 Gqb59iUBF62FS0bzp5MKFHvYvHjahgbYJC9zlO8l2N3PloPpdpswwjW4VZqLgg== 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 v4 03/45] media: sun6i-csi: Tidy up platform code Date: Fri, 15 Apr 2022 17:27:29 +0200 Message-Id: <20220415152811.636419-4-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 | 98 ++++++++++--------- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 4 +- 2 files changed, 56 insertions(+), 46 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..becd8d17f8eb 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -153,25 +153,25 @@ 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); - clk_disable_unprepare(csi_dev->clk_ram); + clk_disable_unprepare(csi_dev->clock_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); + clk_rate_exclusive_put(csi_dev->clock_mod); + clk_disable_unprepare(csi_dev->clock_mod); reset_control_assert(csi_dev->reset); return 0; } - ret = clk_prepare_enable(csi_dev->clk_mod); + ret = clk_prepare_enable(csi_dev->clock_mod); if (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(csi_dev->clk_mod, 300000000); + clk_set_rate_exclusive(csi_dev->clock_mod, 300000000); - ret = clk_prepare_enable(csi_dev->clk_ram); + ret = clk_prepare_enable(csi_dev->clock_ram); if (ret) { dev_err(csi_dev->dev, "Enable clk_dram_csi clk err %d\n", ret); goto clk_mod_disable; @@ -188,11 +188,11 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) return 0; clk_ram_disable: - clk_disable_unprepare(csi_dev->clk_ram); + clk_disable_unprepare(csi_dev->clock_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); + clk_rate_exclusive_put(csi_dev->clock_mod); + clk_disable_unprepare(csi_dev->clock_mod); return ret; } @@ -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_interrupt(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,73 +815,82 @@ 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_clk(&pdev->dev, "bus", io_base, + csi_dev->regmap = devm_regmap_init_mmio_clk(dev, "bus", 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_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(csi_dev->clk_mod); + /* Clocks */ + + csi_dev->clock_mod = devm_clk_get(dev, "mod"); + if (IS_ERR(csi_dev->clock_mod)) { + dev_err(dev, "failed to acquire module clock\n"); + return PTR_ERR(csi_dev->clock_mod); } - 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(csi_dev->clk_ram); + csi_dev->clock_ram = devm_clk_get(dev, "ram"); + if (IS_ERR(csi_dev->clock_ram)) { + dev_err(dev, "failed to acquire ram clock\n"); + return PTR_ERR(csi_dev->clock_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_interrupt, 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); } @@ -903,16 +911,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"); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index e4e7ac6c869f..945d0cb5ab39 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -51,8 +51,8 @@ struct sun6i_csi_device { struct sun6i_video video; struct regmap *regmap; - struct clk *clk_mod; - struct clk *clk_ram; + struct clk *clock_mod; + struct clk *clock_ram; struct reset_control *reset; int planar_offset[3]; From patchwork Fri Apr 15 15:27: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: 12815033 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 79874C433EF for ; Fri, 15 Apr 2022 15:28:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355094AbiDOPa4 (ORCPT ); Fri, 15 Apr 2022 11:30:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37484 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355051AbiDOPay (ORCPT ); Fri, 15 Apr 2022 11:30:54 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 53B42D3AE6; Fri, 15 Apr 2022 08:28:25 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 0A9E4E000D; Fri, 15 Apr 2022 15:28:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036504; 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=LT0EhgXq3R2l9e4oXz3V0FKtUtVuZ2/Gch2vNg9Dl2A=; b=FHSaqiWxImF5DecN39A8JgDZ9U/pYYsLbQrLw3JkbPjVn7/b5Y5O+Cyu8QgtFi3xFtZOUE fRwDqQ+4S6yOqT6BiPS87ptJgoeWp+9ZrARGu37qYh8T3QRueSEH9FS1K5+rX540xvNryT orARlEVOS8ZbBunZMBc0fSaej3/WhWD7o1Cv8ZpyQsuG+gGangake1JdxyB6S4Q03EuIcb kXlzTB/PwdlxmEL4+ZfJDag0UhES7BiPPAyhdQLwE6fqKutQGCWW7IxuqsXo9U2wLMwMlY e21mvvVUXnSBl6jaeeJninnjG0IeRsnnmk0b1b5469zalk4yMvmfp6+r63+R3w== 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 v4 04/45] media: sun6i-csi: Always set exclusive module clock rate Date: Fri, 15 Apr 2022 17:27:30 +0200 Message-Id: <20220415152811.636419-5-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 becd8d17f8eb..827583a30ad0 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->clock_ram); - if (of_device_is_compatible(dev->of_node, - "allwinner,sun50i-a64-csi")) - clk_rate_exclusive_put(csi_dev->clock_mod); clk_disable_unprepare(csi_dev->clock_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->clock_mod, 300000000); - ret = clk_prepare_enable(csi_dev->clock_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->clock_ram); clk_mod_disable: - if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clk_rate_exclusive_put(csi_dev->clock_mod); clk_disable_unprepare(csi_dev->clock_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 clock_mod_rate; void __iomem *io_base; int ret; int irq; @@ -850,28 +843,53 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, return PTR_ERR(csi_dev->clock_ram); } + if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) + clock_mod_rate = 300000000; + else + clock_mod_rate = 297000000; + + ret = clk_set_rate_exclusive(csi_dev->clock_mod, clock_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_clock_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_clock_rate_exclusive; + } ret = devm_request_irq(dev, irq, sun6i_csi_interrupt, 0, SUN6I_CSI_NAME, csi_dev); if (ret) { dev_err(dev, "failed to request interrupt\n"); - return ret; + goto error_clock_rate_exclusive; } return 0; + +error_clock_rate_exclusive: + clk_rate_exclusive_put(csi_dev->clock_mod); + + return ret; +} + +static void sun6i_csi_resources_cleanup(struct sun6i_csi_device *csi_dev) +{ + clk_rate_exclusive_put(csi_dev->clock_mod); } static int sun6i_csi_probe(struct platform_device *platform_dev) @@ -891,7 +909,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) @@ -899,6 +926,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 Apr 15 15:27: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: 12815036 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 AA7F3C433F5 for ; Fri, 15 Apr 2022 15:28:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355124AbiDOPbA (ORCPT ); Fri, 15 Apr 2022 11:31:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37506 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355073AbiDOPaz (ORCPT ); Fri, 15 Apr 2022 11:30:55 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 721CDD4460; Fri, 15 Apr 2022 08:28:26 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 29A5AE000B; Fri, 15 Apr 2022 15:28:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036505; 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=hw1/hVU6DiJXgHDMvHlbfvoQyLbmP32q3m6LkbOfzxk=; b=l1Ldc4Rx8DRgLfj7ztQACo5Pz6sTEoYE2PmsS9Ecca65at5Gd0VjJRtmbwLNExm82tFBJM 5YCy/NyFnf5Wbq8DKzUGUIxzfjgw0GinZ8y4jf2DEsd0qemh4TfdnKdiEQgeaBXma+yq3z Kei3Dx7H+gxnz6uOiY4j7CJx1M+MhtORJZKJDCyJgrjBPye+N8VfXGIM8blLnQGkedJ0RO n2RiAU+TGFBVel1plbkIeMqWCCacTQkHhSmeelorYDm4xIGePQZ/7vtOhNaDF8Smr+RNr0 ktQM8eV9o4I10TQmcfGms4DFODYRehUoRWPHD/rvUqlJjhgBqOCYKPnY+a0w+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 v4 05/45] media: sun6i-csi: Define and use variant to get module clock rate Date: Fri, 15 Apr 2022 17:27:31 +0200 Message-Id: <20220415152811.636419-6-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 | 47 ++++++++++++++----- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 4 ++ 2 files changed, 39 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 827583a30ad0..46d92b925cc8 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -811,11 +811,15 @@ 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 clock_mod_rate; + const struct sun6i_csi_variant *variant; void __iomem *io_base; int ret; int irq; + variant = of_device_get_match_data(dev); + if (!variant) + return -EINVAL; + /* Registers */ io_base = devm_platform_ioremap_resource(platform_dev, 0); @@ -843,12 +847,8 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, return PTR_ERR(csi_dev->clock_ram); } - if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clock_mod_rate = 300000000; - else - clock_mod_rate = 297000000; - - ret = clk_set_rate_exclusive(csi_dev->clock_mod, clock_mod_rate); + ret = clk_set_rate_exclusive(csi_dev->clock_mod, + variant->clock_mod_rate); if (ret) { dev_err(dev, "failed to set mod clock rate\n"); return ret; @@ -931,12 +931,35 @@ static int sun6i_csi_remove(struct platform_device *pdev) return 0; } +static const struct sun6i_csi_variant sun6i_a31_csi_variant = { + .clock_mod_rate = 297000000, +}; + +static const struct sun6i_csi_variant sun50i_a64_csi_variant = { + .clock_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 945d0cb5ab39..a76b545f2aa4 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -58,6 +58,10 @@ struct sun6i_csi_device { int planar_offset[3]; }; +struct sun6i_csi_variant { + unsigned long clock_mod_rate; +}; + /** * sun6i_csi_is_format_supported() - check if the format supported by csi * @csi: pointer to the csi From patchwork Fri Apr 15 15:27: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: 12815037 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 F13D8C433EF for ; Fri, 15 Apr 2022 15:28:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355137AbiDOPbC (ORCPT ); Fri, 15 Apr 2022 11:31:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37538 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355093AbiDOPa5 (ORCPT ); Fri, 15 Apr 2022 11:30:57 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 25480D4448; Fri, 15 Apr 2022 08:28:27 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 46D7FE000C; Fri, 15 Apr 2022 15:28:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036506; 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=PxT7HZrQYzk3vV90fOmSjZ6R1dXpanCdMetMbem4pcM=; b=NSVOCdnjSPimfhMPMKA4ry0VlWecxDYKM6GU/ChAfwAuqvzAY4BSJH/UUSM7e5711gjTSj KL/LCLnKc9uyw09Qvg76p+NkOk03JvZ863j5N72kmAHkQ3izCmo3s1oq27KLg5eLf9VmAJ 0tlrWx5HmvgOWdkCgKa+R93EhPDfyMhU0Y2Wh8rjBOwc4sP9H7Y22kO3cFyjMs0663+NLY 52VMprlrv5Q8QasT+P2umkNAHyYBPP7wjEasRBAcQhC/py8YT5AfJpC/vKSJxCK4fy44MG QFiRjX08TzHi49R/fIwUoC8mbQPsiIQ7riz9vqki8qqg1PUT26kfZZzjsWeDSA== 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 v4 06/45] media: sun6i-csi: Use runtime pm for clocks and reset Date: Fri, 15 Apr 2022 17:27:32 +0200 Message-Id: <20220415152811.636419-7-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Reviewed-by: Jernej Skrabec --- .../media/platform/sunxi/sun6i-csi/Kconfig | 2 +- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 84 +++++++++++++------ 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/Kconfig b/drivers/media/platform/sunxi/sun6i-csi/Kconfig index 0345901617d4..965fbd937841 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/Kconfig +++ b/drivers/media/platform/sunxi/sun6i-csi/Kconfig @@ -2,7 +2,7 @@ config VIDEO_SUN6I_CSI tristate "Allwinner V3s Camera Sensor Interface driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV && COMMON_CLK && HAS_DMA + depends on VIDEO_DEV && COMMON_CLK && HAS_DMA && PM 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 46d92b925cc8..dcc9e7a125e2 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->clock_ram); - clk_disable_unprepare(csi_dev->clock_mod); - reset_control_assert(csi_dev->reset); return 0; } - ret = clk_prepare_enable(csi_dev->clock_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->clock_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->clock_ram); -clk_mod_disable: - clk_disable_unprepare(csi_dev->clock_mod); - return ret; } static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_device *csi_dev, @@ -800,6 +778,56 @@ static irqreturn_t sun6i_csi_interrupt(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->clock_ram); + clk_disable_unprepare(csi_dev->clock_mod); + + 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->clock_mod); + if (ret) { + dev_err(dev, "failed to enable module clock\n"); + goto error_reset; + } + + ret = clk_prepare_enable(csi_dev->clock_ram); + if (ret) { + dev_err(dev, "failed to enable ram clock\n"); + goto error_clock_mod; + } + + return 0; + +error_clock_mod: + clk_disable_unprepare(csi_dev->clock_mod); + +error_reset: + reset_control_assert(csi_dev->reset); + + return ret; +} + +static const struct dev_pm_ops sun6i_csi_pm_ops = { + .runtime_suspend = sun6i_csi_suspend, + .runtime_resume = sun6i_csi_resume, +}; + static const struct regmap_config sun6i_csi_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -879,6 +907,10 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, goto error_clock_rate_exclusive; } + /* Runtime PM */ + + pm_runtime_enable(dev); + return 0; error_clock_rate_exclusive: @@ -889,6 +921,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->clock_mod); } @@ -971,6 +1004,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 Apr 15 15:27:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12815038 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 5D708C433FE for ; Fri, 15 Apr 2022 15:28:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355140AbiDOPbD (ORCPT ); Fri, 15 Apr 2022 11:31:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37540 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355096AbiDOPa5 (ORCPT ); Fri, 15 Apr 2022 11:30:57 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C242AD445C; Fri, 15 Apr 2022 08:28:28 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 788DAE0012; Fri, 15 Apr 2022 15:28:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036507; 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=23yNi58FWraXJ7AbCazkNdV9n1QRLk2mhxc/j0XpgT0=; b=b+bHS5YnvX846+C5HZFR+5dkwKHtaL4+XeOGKZo6iNM1tInaNKJ2OOlF2C3IivM+oUCTln 88JY/NyycUDo6yN02D/aCUMBt9l9se7P0+4qsEESPYrCGvpFispDDRxvTSIwxdHB4pOev2 jTXZ6Jap6xUv3HgrOwB5Xe6t2CvMcV20KKdbXbrdBw/VfzffemjZLjqXvg4gEDGo7Ns0hH SdKd+SOERlkYnbMo2/IcGBuwQxRclQnLLFu8hrYWyRwYapCWGN3stO+gU6jWaWnnv4RBij 7UYj9ItjcUEOF6NAoqcueHW3Dp/iATeGCYHBW8Onn4JmLbP+e3gezEMjowvI/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 v4 07/45] media: sun6i-csi: Tidy up Kconfig Date: Fri, 15 Apr 2022 17:27:33 +0200 Message-Id: <20220415152811.636419-8-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 and update the description. Signed-off-by: Paul Kocialkowski Acked-by: Jernej Skrabec --- drivers/media/platform/sunxi/sun6i-csi/Kconfig | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/Kconfig b/drivers/media/platform/sunxi/sun6i-csi/Kconfig index 965fbd937841..fe50f9bb8fd1 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/Kconfig +++ b/drivers/media/platform/sunxi/sun6i-csi/Kconfig @@ -1,13 +1,15 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_SUN6I_CSI - tristate "Allwinner V3s Camera Sensor Interface driver" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV && COMMON_CLK && HAS_DMA && PM + tristate "Allwinner A31 Camera Sensor Interface (CSI) Driver" + depends on V4L_PLATFORM_DRIVERS && VIDEO_DEV depends on ARCH_SUNXI || COMPILE_TEST + depends on PM && COMMON_CLK && HAS_DMA select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG - select REGMAP_MMIO select V4L2_FWNODE + select REGMAP_MMIO help - Support for the Allwinner Camera Sensor Interface Controller on V3s. + Support for the Allwinner A31 Camera Sensor Interface (CSI) + controller, also found on other platforms such as the A83T, H3, + V3/V3s or A64. From patchwork Fri Apr 15 15:27:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12815039 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 E3136C433EF for ; Fri, 15 Apr 2022 15:28:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355145AbiDOPbE (ORCPT ); Fri, 15 Apr 2022 11:31:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37590 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355113AbiDOPa7 (ORCPT ); Fri, 15 Apr 2022 11:30:59 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 46DBED3AE6; Fri, 15 Apr 2022 08:28:29 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 99F72E000E; Fri, 15 Apr 2022 15:28:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036508; 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=f/85jkQeR3l9hsK0wjMhb2D1WQGSqgYe7ss33bUuh2s=; b=mTdPrHglxnlDHLB6mog4vf8HMADAKhlyEmVtHOd6fGbqHkipzX1SPejqs9o/i7Pu631yiu 6vDdQj8xTV/n3YT24uVRFixwVh/9Nwjy17yAlafrMLK34q6Vspc01XyrovDgGZX7IJdyfc vNGcAFAEpt/vyfRx9o1+5ZWvaIqLkJn0IhtT2b5H4hbwH/8vbumUi3oWbf6YvYDnbpd3y0 3KUZnIB/qcHRNUrpoZ0JaLFgfmoHI2Kk+toUv9YYSSr4XaO9mdkyQ4HiEHuGUhEBr6ccbi UgsNuC8YsHKRDWbLjnrI9tUNR76Cay3Vojo3smaCgb7wxyjuPddUrr0r5PCVIg== 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 v4 08/45] media: sun6i-csi: Tidy up v4l2 code Date: Fri, 15 Apr 2022 17:27:34 +0200 Message-Id: <20220415152811.636419-9-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 dcc9e7a125e2..902a69cc27fe 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_interrupt(int irq, void *private) @@ -942,7 +960,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 Apr 15 15:27:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12815041 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 4364DC433FE for ; Fri, 15 Apr 2022 15:28:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355218AbiDOPb0 (ORCPT ); Fri, 15 Apr 2022 11:31:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37648 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355155AbiDOPbK (ORCPT ); Fri, 15 Apr 2022 11:31:10 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8446BD4476; Fri, 15 Apr 2022 08:28:31 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id D33D3E0008; Fri, 15 Apr 2022 15:28:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036509; 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=uppFXxqEu6pK3jES2UFtu5sjjWvhTtswSsS5+yNpF0w=; b=oh3YHT9g4/AZiONRm8ryFpYxADg9cxMJL343vp20tn+vPUtLY8RGZ+y+fS5Jet9GVp+TyC ED3s3T2/xY1xyNWJCsNcs17cPl7ViwieckJEFNn+5EGy3Cqk3sS2YgeIP/EEQ0Kb2TysvN x0GFpvlns8PtaE1SrInDqxPeBEJ35vU367y4jzi/UbzkJ6zpgGG4jYdE2zhuTukmj3dWWF L4Ox26C76lREC77kSuL0O0K+0VFDASBBdF9DUWevqYG6Mbzu9jH08Bu0hQ7hSl9Xgv3D+q yyuoVqnN0dqko4FKvtLCz4E2yoWWhXGgAiHeJqftpFiZXZ8k68izoT03K/BjkQ== 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 v4 09/45] media: sun6i-csi: Tidy up video code Date: Fri, 15 Apr 2022 17:27:35 +0200 Message-Id: <20220415152811.636419-10-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 | 512 ++++++++++-------- .../platform/sunxi/sun6i-csi/sun6i_video.h | 18 +- 3 files changed, 288 insertions(+), 246 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 902a69cc27fe..f1cf9f2538a0 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 314b56ca5b33..22243961d4d0 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,165 +310,173 @@ 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; - if (pixfmt->pixelformat == V4L2_PIX_FMT_JPEG) - pixfmt->colorspace = V4L2_COLORSPACE_JPEG; + if (pix_format->pixelformat == V4L2_PIX_FMT_JPEG) + pix_format->colorspace = V4L2_COLORSPACE_JPEG; else - pixfmt->colorspace = V4L2_COLORSPACE_SRGB; + pix_format->colorspace = V4L2_COLORSPACE_SRGB; - pixfmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - pixfmt->quantization = V4L2_QUANTIZATION_DEFAULT; - pixfmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; + 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, @@ -465,9 +485,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); @@ -478,44 +497,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); @@ -532,9 +553,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) { @@ -571,20 +591,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; } @@ -598,90 +618,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 Apr 15 15:27:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12815042 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 EDE7AC4332F for ; Fri, 15 Apr 2022 15:29:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355159AbiDOPb1 (ORCPT ); Fri, 15 Apr 2022 11:31:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37926 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355156AbiDOPbK (ORCPT ); Fri, 15 Apr 2022 11:31:10 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8DCC4D4C94; Fri, 15 Apr 2022 08:28:32 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 00DF3E0009; Fri, 15 Apr 2022 15:28:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036511; 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=f1FqPOCbJDygBU42OQ1OAziM2T5/8WcdFJs5e17auwQ=; b=lMKwmyQ0TofB/+yE9fRyDtSX5bUNLNgRKIKTsKAQwqNwGJwOHfxh5325ZiN5wpnKEfODxn t8Doaa8OLlEEAR7PYzRY+WMFvTwpkpHE7d7i2h2glNEDAdOI2+4ZwQAaPakPk3RmyEeF+Y gOPbagq/i0gZTG1fIsaxahNb7YCUBV21AnDZPhyXFSeogtJOvfRucJi2eWnuR1tC3UE79N 2AsM0bV9XVOo4T0WojXqOvjFkrBUooqI6qVUpJyUMjrwvLohSqFMd7G4985MhOQWGGaVfZ 26CTmA1W2KzpW6+jnfxkMkM2Hw/poJp0TzY8/hXt7wPWDA3L5twViKazBv3zrw== 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 v4 10/45] media: sun6i-csi: Pass and store csi device directly in video code Date: Fri, 15 Apr 2022 17:27:36 +0200 Message-Id: <20220415152811.636419-11-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 f1cf9f2538a0..198275e09865 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_interrupt(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 22243961d4d0..e6c85fcc65bb 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; @@ -413,7 +418,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; @@ -424,7 +430,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); } @@ -489,7 +496,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)) @@ -505,7 +513,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; } @@ -525,7 +533,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); @@ -537,7 +546,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); @@ -574,15 +583,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; } @@ -590,10 +600,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); @@ -602,7 +612,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); @@ -620,9 +630,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; @@ -631,8 +641,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; @@ -664,7 +672,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; @@ -697,7 +705,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) { @@ -719,8 +727,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 Apr 15 15:27:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12815040 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 8F06DC433F5 for ; Fri, 15 Apr 2022 15:28:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242542AbiDOPbZ (ORCPT ); Fri, 15 Apr 2022 11:31:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37972 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355159AbiDOPbL (ORCPT ); Fri, 15 Apr 2022 11:31:11 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6D5EDD4C9A; Fri, 15 Apr 2022 08:28:33 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 513F0E0016; Fri, 15 Apr 2022 15:28:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036512; 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=p/G3Lv5aXmpaUoYeX8MRq+c6XCpBmVOvXeLJxUHHzd0=; b=Z3YIxE+Elv/LhefhNAdaJTccscQKVVtnBYvmQ4D5CKJUqFRnmuZqBn+A1wCUW22mlHJk/L SLq4FtjJdGO7oWtTlxjd7Fiw18nUo2VM6t9jrA3yQoUCBoZrsn1UU5gacCpBJsyk49IJFp fjLC+b/F9m8dyCHK7vCP5X315ZuXV1WM0zmIPtg8GZgR82LxVvIl7cDv2CynEg53UaK+Ns d+7r86QO76QV+PjqIgPBSqqjBb50dd+ZD+uINYJM8dLggHNOfEZsjRXc3o4cz3zlj6Flom +TKFDQ1mB5EBT407CVS4mrMzQ0PYjWrjicfqNGsylKvR+Y1aKkC1WaGyI8oQ1g== 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 v4 11/45] media: sun6i-csi: Register the media device after creation Date: Fri, 15 Apr 2022 17:27:37 +0200 Message-Id: <20220415152811.636419-12-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- 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 198275e09865..e59ee3e3f372 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 Apr 15 15:27:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12815043 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 0E46EC433F5 for ; Fri, 15 Apr 2022 15:29:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1350410AbiDOPb2 (ORCPT ); Fri, 15 Apr 2022 11:31:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38182 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355180AbiDOPbT (ORCPT ); Fri, 15 Apr 2022 11:31:19 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E2E03D4474; Fri, 15 Apr 2022 08:28:34 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 66497E000D; Fri, 15 Apr 2022 15:28:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036513; 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=r7KuNEhxQ7zZ4XXrUpnB6gfWTPypBR8BHM6o/MGYzXM=; b=O30wxWs6YWbhqcc8noqeF5nhE6DP0dvJeopLFeOuyB8r36l+jOrUkEVy2uXlhhggIlqTWR EvTr6nLTNBYEaZMToSQGctR1sC/JKRYSCGBpVgbniTu1bBtD009SepHboQyiGHX2gpsq63 TFf9AvGPQs9oN7FX5g2s6/CqszVx7BOkqUxSP2w0dvwyFvEXr9rQcUtZVnXBsRQpdpza4K a5mkl6oYklchj1tAwe1Dt6Sl54A9VLSasYDzNzzXOcO1G3IZqfEkBZ+AkyIfbwsBZa0pp9 vlK7CupaSHIKAo8uuDwlBQ3u3kTbEhXqphgES1kvPfvOitIgHnVcK3m0jz62yg== 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 v4 12/45] media: sun6i-csi: Add media ops with link notify callback Date: Fri, 15 Apr 2022 17:27:38 +0200 Message-Id: <20220415152811.636419-13-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- 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 e59ee3e3f372..578714606c2f 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 Apr 15 15:27:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12815044 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 4599AC433EF for ; Fri, 15 Apr 2022 15:29:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355237AbiDOPba (ORCPT ); Fri, 15 Apr 2022 11:31:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37674 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355113AbiDOPbW (ORCPT ); Fri, 15 Apr 2022 11:31:22 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F2D4FD4CBB; Fri, 15 Apr 2022 08:28:35 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 8FD5BE0017; Fri, 15 Apr 2022 15:28:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036514; 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=PqlK7FtREfal2EtJi61PjlujXP2sCS3ZHV9Mtonmi4Q=; b=RDk3DJfetx0vID+ngrfY1EZJIP8YV756vS296CjwP7NRSEV8ZzUnLEkU44q1XIftLT9aA2 nmPRgcmc5Bvg4ak/JB4eDUyaYZ2wQ2J3T9UGjybo3xMBjx7P8d8yvSTTUbDLad23IvpWeV pLwl0DRQJc4Ev23Mh0yXomStTVzcoAoO+BSBjPgE1gyON6CbLfTJyPd0PDyVTrbxVhi+GI XElpdo6aosztBUUyAjmcYxao2Av3/9rfnWddGgfRQGLlZ7xwifXQjyeHqBf3xOlHav/M5Q 21jB+YD/uY5PuqG08q2xd4aasHJ0FnDKsmZjlvMnXq00Zn1NBEarNokeJhjbjg== 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 v4 13/45] media: sun6i-csi: Introduce and use video helper functions Date: Fri, 15 Apr 2022 17:27:39 +0200 Message-Id: <20220415152811.636419-14-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Reviewed-by: Jernej Skrabec --- .../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 e6c85fcc65bb..e47eeb27dc4e 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 Apr 15 15:27:40 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12815046 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 8186FC433F5 for ; Fri, 15 Apr 2022 15:29:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355288AbiDOPbe (ORCPT ); Fri, 15 Apr 2022 11:31:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37646 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355200AbiDOPbX (ORCPT ); Fri, 15 Apr 2022 11:31:23 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 33858D3AE6; Fri, 15 Apr 2022 08:28:36 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id BC932E0004; Fri, 15 Apr 2022 15:28:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036515; 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=28LC4sY4AyPvmWPRrV178P1Cw+vPtjy0bpPYGlIj5lQ=; b=eIJMOGuF9Vu9If265Qj7CfDPmN9NJjxocf3VrpUY7Ti7RitvoMTO8bePJMQKpagkv8QiL7 ukYaFw6OiHcnrb1idu+SSxkSTL2k/pJKeuyxTJbiJq35uqOAXNxijkoNZOH83WSHnVw7+O 8KwPZJx9ebZ5anEf7sq1Wr1FsHKzpUSPlPRYNlgk6jC0/FMcOcJyqRymQ7OhmkU6VglZRu /17R5DH/6vwTG2gN/nJNFXGrt/Tad6ZvmPrdy9Tioqu+vrXjX1dsEvF3CSZ2kZT34ylG7P 6p9vQJIZ0+a7Wu6bGfGD+8gcb8mF1DhFfz0+LDtZ5WMqBdf5j+/jYGEpSs5VyA== 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 v4 14/45] media: sun6i-csi: Move csi buffer definition to main header file Date: Fri, 15 Apr 2022 17:27:40 +0200 Message-Id: <20220415152811.636419-15-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 a76b545f2aa4..f3d9dc8f368d 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 e47eeb27dc4e..636e35406d91 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 Apr 15 15:27:41 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12815045 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 AE999C433EF for ; Fri, 15 Apr 2022 15:29:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355282AbiDOPbd (ORCPT ); Fri, 15 Apr 2022 11:31:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37648 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230406AbiDOPbX (ORCPT ); Fri, 15 Apr 2022 11:31:23 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7C755D5557; Fri, 15 Apr 2022 08:28:38 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id EBF2DE000C; Fri, 15 Apr 2022 15:28:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036516; 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=AwUrbk9xN7kWCavabWhVUg8awWsKfRcf5Qh4VFDHSYg=; b=C1/bzxmQK7wcYkDQkjj6tUZVz+WVzJYTqAREMSKC5hBO0qzwINn8TsJpw8fTbJyqvAySAD HrZVlDHmRUeER8xta11h69T3ysCRC0QByqAc4EA3Zdm0DC233BUqJ48tA2IAUtPw1vy6FH UH0xzcYfJjNtM9xB8/jd7aeTzix65FOuuEdIZQDzsdJriEDfzpQznHG0t8Ba6GS1AZFBFW cQHqdM5JD6MkSxrleCiMjfmSnvevQaf9Re44TidY4rtgL9r/hZoNpsUJX4iUscYIijZULS 7gHTIFXpFLj5nE0jCElaIRgl5wBt9QKUYC4A7iP9pIwWpr2JpQRjkzSegCKRoA== 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 v4 15/45] media: media-entity: Add helper to get a single enabled link Date: Fri, 15 Apr 2022 17:27:41 +0200 Message-Id: <20220415152811.636419-16-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org In a situation where multiple links can be connected to the same pad of an entity, drivers might need to ensure that only a single link is enabled to apply appropriate routing (when the hardware can only use one at a time). Add a helper to return the single enabled link of an entity given a specific pad index, which errors out when zero or more than one link candidates are found. Signed-off-by: Paul Kocialkowski --- drivers/media/mc/mc-entity.c | 26 ++++++++++++++++++++++++++ include/media/media-entity.h | 13 +++++++++++++ 2 files changed, 39 insertions(+) diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index 8ab0913d8d82..dafd99486d7c 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -878,6 +878,32 @@ media_entity_find_link(struct media_pad *source, struct media_pad *sink) } EXPORT_SYMBOL_GPL(media_entity_find_link); +struct media_link * +media_entity_get_single_enabled_link(struct media_entity *entity, + u16 pad_index) +{ + struct media_link *candidate = ERR_PTR(-ENODEV); + struct media_link *link; + + list_for_each_entry(link, &entity->links, list) { + struct media_pad *pad = link->sink->entity == entity ? + link->sink : link->source; + + if (pad->index != pad_index || + !(link->flags & MEDIA_LNK_FL_ENABLED)) + continue; + + /* Error out with more than a single candidate. */ + if (candidate != ERR_PTR(-ENODEV)) + return ERR_PTR(-ENXIO); + + candidate = link; + } + + return candidate; +} +EXPORT_SYMBOL_GPL(media_entity_get_single_enabled_link); + struct media_pad *media_entity_remote_pad(const struct media_pad *pad) { struct media_link *link; diff --git a/include/media/media-entity.h b/include/media/media-entity.h index 742918962d46..ee87224d4a89 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h @@ -847,6 +847,19 @@ int media_entity_setup_link(struct media_link *link, u32 flags); struct media_link *media_entity_find_link(struct media_pad *source, struct media_pad *sink); +/** + * media_entity_get_single_enabled_link - Get a single link for an entity pad + * @entity: The entity + * @pad_index: The index of the entity's pad expected to take part in link + * + * Return: returns a pointer to the single enabled link with the entity's pad. + * If no such link exists, returns a pointer error with %-ENODEV. + * If more than a single link exist, returns a pointer error with %-ENXIO. + */ +struct media_link * +media_entity_get_single_enabled_link(struct media_entity *entity, + u16 pad_index); + /** * media_entity_remote_pad - Find the pad at the remote end of a link * @pad: Pad at the local end of the link From patchwork Fri Apr 15 15:27:42 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12815047 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 781D9C433FE for ; Fri, 15 Apr 2022 15:29:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S244190AbiDOPbh (ORCPT ); Fri, 15 Apr 2022 11:31:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38334 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355212AbiDOPbX (ORCPT ); Fri, 15 Apr 2022 11:31:23 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 68778D557B; Fri, 15 Apr 2022 08:28:39 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 11794E0007; Fri, 15 Apr 2022 15:28:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036518; 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=CqGA+Tw7mY0TqSS6lzLjcDTXNArG5wj/IKi4y717LKw=; b=Rl9a+byXDOJWLAWj4ERtdeV1FjE4Wh9IajiZi+HI9nXgjPwPl9AvPapykIyXkFXicZK0u7 IS1g7PBF6764YUy3bAnfRzNT+QX+uiS7wozFyZFaZaNVqlwVIWsNIRLBZUfP4QOT3z0Tx+ NKE9YTtEvxIhloMqnsLGaZe+27ZVXrUCZ9zmPew1XIY2j+z6fDP6RbiMmMFkilsENXmS8j E2vofj/NENbbARQDzXoDn68ZQtwv8gKzQqaLFFq1Sq2o/682x674NOD2fNXNaRbWFBWTkI WsrN03dxY+uEWO4NJ2/9TMCNiESQcbZdRv+mZLY4nIOSJ/TS91CbUSBmBL4iIQ== 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 v4 16/45] media: sun6i-csi: Add bridge v4l2 subdev with port management Date: Fri, 15 Apr 2022 17:27:42 +0200 Message-Id: <20220415152811.636419-17-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 | 451 ++++++++++++++++++ .../sunxi/sun6i-csi/sun6i_csi_bridge.h | 49 ++ .../platform/sunxi/sun6i-csi/sun6i_video.c | 19 + 6 files changed, 549 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 578714606c2f..f74984c8fc3b 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_parallel.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_parallel.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); @@ -979,8 +852,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); @@ -991,6 +878,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 f3d9dc8f368d..da0c758252e7 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..bba825db8322 --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c @@ -0,0 +1,451 @@ +// 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 sun6i_csi_bridge *bridge = &csi_dev->bridge; + struct media_entity *bridge_entity = &bridge->subdev.entity; + struct device *dev = csi_dev->dev; + struct v4l2_subdev *source_subdev; + struct media_link *link; + /* Initialize to 0 to use both in disable label (ret != 0) and off. */ + int ret = 0; + + /* Source */ + + link = media_entity_get_single_enabled_link(bridge_entity, + SUN6I_CSI_BRIDGE_PAD_SINK); + if (IS_ERR(link)) { + dev_err(dev, + "zero or more than a single source connected to the bridge\n"); + return PTR_ERR(link); + } + + source_subdev = media_entity_to_v4l2_subdev(link->source->entity); + + 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: + + 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 const struct media_entity_operations sun6i_csi_bridge_entity_ops = { + .link_validate = v4l2_subdev_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_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; + + 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..f9bf87bf3667 --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h @@ -0,0 +1,49 @@ +/* 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; +}; + +/* 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 636e35406d91..e682d84ed263 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -636,6 +636,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; @@ -719,8 +720,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 Apr 15 15:27:43 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12815049 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 73253C433EF for ; Fri, 15 Apr 2022 15:29:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355247AbiDOPbl (ORCPT ); Fri, 15 Apr 2022 11:31:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38562 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355132AbiDOPbb (ORCPT ); Fri, 15 Apr 2022 11:31:31 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A50EDD59A3; Fri, 15 Apr 2022 08:28:40 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 38B56E000E; Fri, 15 Apr 2022 15:28:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036519; 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=vURikkfj13O4EGOpk0sDHiornIjwBHS/A5Jo1JwZO50=; b=n6A6JiTmSiIoF0eA/z0xo6T+K19jW/3qpBjNSUysoUTJT9Ww2ReNOMGWrPmf+lhj1DVdAm hkiFx7Z5Mt+FR5pfPjq49zK+hXyWl41CPGxCFrg4mXf/Nm58Nq33EB9MG7t3oSSWkckRYV DuCZ66AXEEUcQcJ76kFk8LTUvBx6i4Pqxf9TeNIHjC3AyJqadtbC0m0YdonBH92S0kGNnx DqzTHCataaKim9fEdbbWg5RrTTWRmT/0n4ox7H0qdPIy4OoKO+kKAhluld0vhty22vbu/d l2rkkAC4n5HcXhS4GI3pPy2uSV9YUpozph5DLJWCXzFJuAgbNhopvTZ5SYxu3A== 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 v4 17/45] media: sun6i-csi: Rename sun6i_video to sun6i_csi_capture Date: Fri, 15 Apr 2022 17:27:43 +0200 Message-Id: <20220415152811.636419-18-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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} (59%) 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 f74984c8fc3b..62f65867c771 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_interrupt(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); @@ -856,7 +856,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; @@ -878,7 +878,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 da0c758252e7..422d7b9939f9 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 *clock_mod; 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 59% rename from drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c rename to drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c index e682d84ed263..cb29ddf6af27 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); @@ -403,43 +404,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; @@ -450,16 +451,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; @@ -467,17 +468,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, @@ -496,20 +497,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; @@ -520,7 +521,7 @@ static int sun6i_video_open(struct file *file) goto error_v4l2_fh; } - mutex_unlock(&video->lock); + mutex_unlock(&capture->lock); return 0; @@ -528,37 +529,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 @@ -566,8 +567,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 = @@ -581,72 +583,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 */ @@ -658,22 +662,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; @@ -689,12 +693,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 */ @@ -702,11 +706,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); @@ -743,17 +747,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 Apr 15 15:27:44 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12815048 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 AF8D4C433F5 for ; Fri, 15 Apr 2022 15:29:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355213AbiDOPbj (ORCPT ); Fri, 15 Apr 2022 11:31:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38536 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355235AbiDOPba (ORCPT ); Fri, 15 Apr 2022 11:31:30 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C0329D59BB; Fri, 15 Apr 2022 08:28:41 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 6CBC2E0013; Fri, 15 Apr 2022 15:28:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036520; 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=jUjQaMo0gxDEGeQugoELE5k8zPMDdRJCPc5uVTwkmzg=; b=ahh+89EkZKgbAQctLoyxsu4eT/h/O6iwTyfCxCKLjgaxl5EbkZmqrgQfiswbT0AXXukP3x XDOfLIDr3DiEZHs0GP6uQi/wJxe/NrjIHyQyDiftX6davwszyqF4X6hRy0E7iQroVni5tT sBGgmty+VoX4cnfJn1bTSloRmy0R3Dni+FKd1ONEX0BS3S8/H49ExCkNSw+lO2WrKu2XQr NmAuHRwHCfIkBxpHxdcJ13O4RprXTgyW7AydKN5bwsPHAj8oi0zFAoTX351CXxZS8L2PBx t2oHosmakPLsPm3WKHYKjpLVOtG0FfPuNaLdfaHZxP1XVezTbem17O/b5PGtYQ== 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 v4 18/45] media: sun6i-csi: Add capture state using vsync for page flip Date: Fri, 15 Apr 2022 17:27:44 +0200 Message-Id: <20220415152811.636419-19-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 62f65867c771..5656faf15d7e 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_interrupt(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 422d7b9939f9..f02656dbfd84 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 cb29ddf6af27..e227940cb66e 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 = { @@ -639,6 +671,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; @@ -648,6 +681,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; @@ -660,13 +698,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); @@ -676,14 +707,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 Apr 15 15:27:45 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12815050 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 DE1E2C433EF for ; Fri, 15 Apr 2022 15:29:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355326AbiDOPbs (ORCPT ); Fri, 15 Apr 2022 11:31:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38570 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355248AbiDOPbb (ORCPT ); Fri, 15 Apr 2022 11:31:31 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2B700D5E8E; Fri, 15 Apr 2022 08:28:42 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 8F27FE0014; Fri, 15 Apr 2022 15:28:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036521; 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=wXhaRmUbjKowxcDXQpq9QiEyyi4YmgRz7MQ5r8qBPdw=; b=MDOJHVTzc8mJtRq3gk5CXk+4Jwg3hHEEVXjalUUevpz7B1a/eaEljN6js/j2lJg8Nt6wFO g/vr8IOIvJz3hL2vpFug3jtuZbL15jDi+sSKUmkPMJ1RvmKh1+e2aX5j6OLTS5HH4ynTKf 1G3k0HRfnTIxanWYG4kA6FxVwT1DQTBhHOcCs9by7vlVAr0u9f340KWX8WwO7znhBDqHx8 3qbxVUKkRz9N4H0sfD57u1hF67ZUwU8BZUjYZNBVqK+0bFG+CRVMLwLHf0CCLhKgYorFPG /uVL5wpPsz6flze6zpxo7k+OP4mWp38OS0k7f5ZwxzROu97xBJWC9IGupS8rtA== 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 v4 19/45] media: sun6i-csi: Rework register definitions, invert misleading fields Date: Fri, 15 Apr 2022 17:27:45 +0200 Message-Id: <20220415152811.636419-20-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 5656faf15d7e..c7b53e8099d3 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_interrupt(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 Apr 15 15:27:46 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12815051 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 4B9C5C433F5 for ; Fri, 15 Apr 2022 15:29:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355331AbiDOPbw (ORCPT ); Fri, 15 Apr 2022 11:31:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37972 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1352749AbiDOPbb (ORCPT ); Fri, 15 Apr 2022 11:31:31 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0AD7AD4464; Fri, 15 Apr 2022 08:28:43 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id AE7E5E0010; Fri, 15 Apr 2022 15:28:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036522; 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=U0FqhegBKfQ1CKLY+sfQO+NmSnevzee52MzjDJaSX4M=; b=o0L+etGxlsyMRCuK9rEUUJh6i+Mj+Wxl9Ypu7jeldtX5ZfaB25A1chvn5yH9FSdyRlSEFM vmxpVY1QmpIE0FqqM2UL2ug+FVnlvhcxTT2HJ/u7yuOiDUzi+8/zqNSWlo9LfRvU79mYGX 5qSMJrNyKziV4gYeTdaqlU5UBOsR6xgYvK+ydpp7Zw5KGdeF0hBBuFSXWGrokB6yuN60Iw 8tjcbWlFlne8QuEOFD2sAVyQftZIO7zlkZX/xhMBco6JmGpPBQAOmUIRJB1ajef4Amx/Yw SEAi9+67pMT+e2droGfS3/xc9gja48n2EuFLezajMjGS+vrzUS1qvhZnTlHAXA== 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 v4 20/45] media: sun6i-csi: Add dimensions and format helpers to capture Date: Fri, 15 Apr 2022 17:27:46 +0200 Message-Id: <20220415152811.636419-21-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 e227940cb66e..acbd0ea62fd5 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 Apr 15 15:27: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: 12815052 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 37D67C433EF for ; Fri, 15 Apr 2022 15:29:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355347AbiDOPcG (ORCPT ); Fri, 15 Apr 2022 11:32:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37648 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355251AbiDOPbc (ORCPT ); Fri, 15 Apr 2022 11:31:32 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 664C8D59B1; Fri, 15 Apr 2022 08:28:45 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id D2566E0009; Fri, 15 Apr 2022 15:28:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036523; 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=wxhTK/Jz0rjIme8apU0IaxEIg/XYW7Kiz+ASODFRNkk=; b=d2oWzuzTlq0CDj2uIsBdahUWK87fUkRqO71z/jJCWPzZvC2zlja5m/Zd+Ei0zcPakkn9Ww TrT9gtsOMUJbG5AavyZyAuTrNehS0jDz0XmF93Md1fMBO9UjWml8cPVfj0BA6HyqzS8edX NtMeVftdX984PdiovuhhrKKmY/IGaGQZp9WNZ1ra27hTP2s0lji2m1Fdv/la6Q30ngINpA LYYaxluM3+G7a/NFSCcl+W8a42DXQO4jD1QH9XJJ8cF++/7yO2OCIqH1XH7vaYt+vhRBi1 I7YCMW6+zO90o+2lFtZMlYegTxdFxI7T+n6r22tzMt5ZuoEoVf7vrie4ujuvBw== 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 v4 21/45] media: sun6i-csi: Implement address configuration without indirection Date: Fri, 15 Apr 2022 17:27:47 +0200 Message-Id: <20220415152811.636419-22-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 c7b53e8099d3..98133c1dbf68 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 f02656dbfd84..44fc4d486877 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -62,8 +62,6 @@ struct sun6i_csi_device { struct clk *clock_mod; struct clk *clock_ram; struct reset_control *reset; - - int planar_offset[3]; }; struct sun6i_csi_variant { @@ -94,14 +92,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 acbd0ea62fd5..7788cbab7810 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 Apr 15 15:27: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: 12815053 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 36DF4C433FE for ; Fri, 15 Apr 2022 15:29:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355372AbiDOPcT (ORCPT ); Fri, 15 Apr 2022 11:32:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38616 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355255AbiDOPbc (ORCPT ); Fri, 15 Apr 2022 11:31:32 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8BE62D5E82; Fri, 15 Apr 2022 08:28:46 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 169FAE0008; Fri, 15 Apr 2022 15:28:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036525; 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=rR2H1Xf4K0BgcchbxdyiXq3RjyCp/LtusqyR0MgUDRA=; b=hI7u74veg0sflihjuybpDSrz72Ox7ET0sDl1VgGkUYZ7rzD/475JKFHjvAgiwFFo9oL9Nc 15NSQpTYb3tLLwzGQYoDME0IoL+0Ucb6wnuv4miAdU6HGBZwsguN5VmwGWKI29W3I0hszn QUmhTxTkRG9Je5f847/Pafz/MTpVvCZDVFKB0xCbYHUCMsKUqyvRmeju4cYP0z0Q2KxXWP zWdD4HI2uSkmsBpZCeW+aV8jGSeOCyg7ZhaZkDxWPzyMozOsZqQeKbkyx02cdxErDawmpX wBKtRU9yYidEbRz4k4wueOEmkzsUEHrrHrtBZ1mj2zy0Yz3SKuKcK3dTvFZTyQ== 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 v4 22/45] media: sun6i-csi: Split stream sequences and irq code in capture Date: Fri, 15 Apr 2022 17:27:48 +0200 Message-Id: <20220415152811.636419-23-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 98133c1dbf68..29892e8c2b9d 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 44fc4d486877..155527961280 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -92,13 +92,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 7788cbab7810..72fcc60d2695 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 Apr 15 15:27: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: 12815054 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 B8512C433EF for ; Fri, 15 Apr 2022 15:30:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S243482AbiDOPdA (ORCPT ); Fri, 15 Apr 2022 11:33:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38646 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355263AbiDOPbc (ORCPT ); Fri, 15 Apr 2022 11:31:32 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A30C4D64D4; Fri, 15 Apr 2022 08:28:47 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 4682BE0015; Fri, 15 Apr 2022 15:28:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036526; 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=2fzMXFp7GnA/U7fJH8F1ljdEdR1zvqkYmKc5yUNRwl4=; b=fpB1K5LTTcVbPKdCHve3eIu0vkvgvWZeB3hOjMqWe1HHGUmBeR0XYc0f7MVKk+lzTEMRve h/VGQeA2SltQJhx5Zfi87uBAbP3PqidNBNXc6ZUPns4U8ghf4tR1ET/ivGsfXBtdzSuoue zhqunrOLpRS+4/3IeEDl1o5FXRVjo2IMMVfrJZb7W+0Rm4axQSnN2xc+iq9AVspBIBZSJ/ BWZvB9RkuVqxTE341RWCVfEnTgtpRrZm9B9lya3CckThejGzFodtsP+YBTxDwyx/ZpPDiz T7TZwxEfQ7x9Cty88rgnMDJ98qDvFNRcMXh7TWhY9pU0XieKI00fjO6o8kuJTQ== 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 v4 23/45] media: sun6i-csi: Move power management to runtime pm in capture Date: Fri, 15 Apr 2022 17:27:49 +0200 Message-Id: <20220415152811.636419-24-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 29892e8c2b9d..7801f5abe47e 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 155527961280..3a4f2b45d267 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -77,13 +77,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 72fcc60d2695..3e5c4f7df48d 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); @@ -639,27 +656,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); @@ -671,19 +681,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 Apr 15 15:27: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: 12815057 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 DE29AC433EF for ; Fri, 15 Apr 2022 15:30:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355205AbiDOPdE (ORCPT ); Fri, 15 Apr 2022 11:33:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38666 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355279AbiDOPbc (ORCPT ); Fri, 15 Apr 2022 11:31:32 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 21463D64E7; Fri, 15 Apr 2022 08:28:48 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 6D38BE0004; Fri, 15 Apr 2022 15:28:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036527; 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=IvrsfVC9khkgyc6+Csmfc4FBVnu5LPjdIsqIv3LIqR0=; b=Ph/MjYAHSius+5CtOLi6KdPJQP1LhKOEKqm4blXqNT9b3qeSubq7PB1wrrSKj5ylXo1+jq xUspCpOkRVam50dNbv+xzJLtjWMSzoFEowdYSXjAJUcil1H94VbJcfYizmof7rFQXeDX02 6ZfYY2mxuWO4mMiW6P+SQ5b3DgYTvKobV9s5lbyzusS0u+w5M6liX5JSWNTj+nmij3MuyI P3DR0nVEI/XP2QrxGiZm4jLBJHWNL0tUG2MnXeJ6s3506S0gGELAYOANj3LIPkeRjmjHbn bTqBahQTLS0x0oNEaaFNdrl1Xn/ckByXfXaqjtuCCw9wR6wUBYEhYtPCaq1ILQ== 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 v4 24/45] media: sun6i-csi: Move register configuration to capture Date: Fri, 15 Apr 2022 17:27:50 +0200 Message-Id: <20220415152811.636419-25-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 7801f5abe47e..940d041351d0 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_parallel.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 3a4f2b45d267..f54ad2f438f8 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; @@ -77,14 +60,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 3e5c4f7df48d..c1d3b352d988 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_parallel.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); - 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; + val = get_csi_input_seq(csi_dev, capture->mbus_code, pixelformat); + cfg |= SUN6I_CSI_CH_CFG_INPUT_YUV_SEQ(val); - sun6i_csi_update_config(csi_dev, &config); + 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); +} + +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)); +} + +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 Apr 15 15:27: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: 12815056 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 E112BC433F5 for ; Fri, 15 Apr 2022 15:30:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355195AbiDOPdC (ORCPT ); Fri, 15 Apr 2022 11:33:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37692 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355283AbiDOPbd (ORCPT ); Fri, 15 Apr 2022 11:31:33 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CB5ECD64F7; Fri, 15 Apr 2022 08:28:50 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 9FC68E0005; Fri, 15 Apr 2022 15:28:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036528; 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=v5zUPacrbUlwxrYJ+3QLMw/I1lu96ffwj/uhaq9Vx2U=; b=RXoXtYv843f6mb0BMSb+6Q+bQAh1BRxB2+Il8ZrAOsVZW7Y34SgX9naWRv96B6utSq8ZW3 uGy4ALzWNA70MXAl3+1KmaT9HIvQnfJ1Mo53v9qZXozf7bjoozc///OLNAlJSex780NDUz M231XfNxNK+FxtRjwte59/L0fS4C4R+1gMdbXeyLIZMpKAjayHmrUBFhUFelfyai6Y7Na5 ay4xgXYTeUu1irSD+96+CUlM5hzIaONuaFCKvz3hbtcyE7M1ufBOhArXPW3u+rTMl7a55g w2/hDgwP143IgEgYA47eCCqMYCY9BXqL1cvexzZUI0KXWbtktaM76HEUWrsuww== 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 v4 25/45] media: sun6i-csi: Rework capture format management with helper Date: Fri, 15 Apr 2022 17:27:51 +0200 Message-Id: <20220415152811.636419-26-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 helpers. Report a raw colorspace for bayer-encoded pixel formats instead of SRGB. Also cleanup the size bound defines while at it. Signed-off-by: Paul Kocialkowski Acked-by: Jernej Skrabec --- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 122 +++++++++--------- .../sunxi/sun6i-csi/sun6i_csi_capture.h | 5 + 2 files changed, 66 insertions(+), 61 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 c1d3b352d988..2aa65a4ddb85 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,55 @@ 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; + const struct v4l2_format_info *info; + 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; + + info = v4l2_format_info(pix_format->pixelformat); + + 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; + + if (pix_format->pixelformat == V4L2_PIX_FMT_JPEG) + pix_format->colorspace = V4L2_COLORSPACE_JPEG; + else if (info && info->pixel_enc == V4L2_PIXEL_ENC_BAYER) + pix_format->colorspace = V4L2_COLORSPACE_RAW; + else + pix_format->colorspace = V4L2_COLORSPACE_SRGB; + + 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,54 +907,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; - - if (pix_format->pixelformat == V4L2_PIX_FMT_JPEG) - pix_format->colorspace = V4L2_COLORSPACE_JPEG; - else - pix_format->colorspace = V4L2_COLORSPACE_SRGB; - - 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; } @@ -925,16 +922,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, @@ -1129,8 +1129,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 */ @@ -1173,13 +1173,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 Apr 15 15:27: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: 12815061 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 813E2C433F5 for ; Fri, 15 Apr 2022 15:30:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236979AbiDOPdL (ORCPT ); Fri, 15 Apr 2022 11:33:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38692 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355285AbiDOPbd (ORCPT ); Fri, 15 Apr 2022 11:31:33 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 350CDD7445; Fri, 15 Apr 2022 08:28:51 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id D2810E000B; Fri, 15 Apr 2022 15:28:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036529; 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=8fg2k3GVSdolI/O8xNOtDfF5xGWkO/n/jXZMLRzxWG4=; b=g8EWycqRX2ARegLmKIo0gdos/efzi5NFzrX1E5xD56qaNNCHNxpEZsC72qf88B+m0l3B/s +Rr1cFMJKY/yb+Vw0iZWozd13m5yWDfyEAL3TZG3QDpu3ArnOXob3TeJaW6OxtqhjTQoVD 0mYscWaxseh3g+Ud/E5mdXHwuw7+rrPF9mI0t9oYhh3fOmiEj40jXL4+dinbr3161xMC0e lo5hSPE/xSJHMRBvb8tFsmlJljCtbCtJvKLrnCoy3SN9Q6jvlvvO38SPN8rYzGWscjpNq+ x7meKxF1vsbRhZkiWXXdl0vvEy1SOYWAyf7B3ix6q0l26OMrfJTcbFfqhStpYw== 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 v4 26/45] media: sun6i-csi: Remove custom format helper and rework configure Date: Fri, 15 Apr 2022 17:27:52 +0200 Message-Id: <20220415152811.636419-27-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 f54ad2f438f8..dd90ffdae5d5 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -60,53 +60,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 2aa65a4ddb85..c4e803a38851 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 Apr 15 15:27: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: 12815060 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 7C046C433FE for ; Fri, 15 Apr 2022 15:30:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1354701AbiDOPdK (ORCPT ); Fri, 15 Apr 2022 11:33:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38566 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355301AbiDOPbj (ORCPT ); Fri, 15 Apr 2022 11:31:39 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8056ED5EB7; Fri, 15 Apr 2022 08:28:52 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 0C94DE000E; Fri, 15 Apr 2022 15:28:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036531; 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=N9Ap9R8Xf7QreTWyG4D1iTf1/X33AGyrJspYSP6S+lI=; b=Tx9c/13XW8tHwZzqAclVW4p0LyvC+TyFcnfIJ3WpIapVq4exOqWvmm11p8nliUONdk17cO RUwbztmtZdDDliHHpqs8b1w3NqdREqo099YaaiUvabKDAFLVQ7ZZfnyN0UQ9FWBiPGcJBJ ltXRGJ4D5/jPICWP9yWo5+yD/C58NaWCihF9lfGMzckWJhB2RVAqXHQDcAcfQ61bYclJbM SE2h/LVoJDRq1dyKoGkORZKnGc28w0ONSBKyc8HSmzDaVevxovkja3uwLwjbpyXV2SShZS 3Y083iYIOIKSOjnxOm+m0xuROR1XN4d5r+bmHxMSO73zPnclUgZb6ImgmoAxVw== 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 v4 27/45] media: sun6i-csi: Add bridge dimensions and format helpers Date: Fri, 15 Apr 2022 17:27:53 +0200 Message-Id: <20220415152811.636419-28-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 bba825db8322..0c1e159537a7 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 f9bf87bf3667..5e6448aa522f 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.h @@ -41,6 +41,13 @@ struct sun6i_csi_bridge { struct sun6i_csi_bridge_source source_parallel; }; +/* 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 Apr 15 15:27: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: 12815059 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 6C236C433EF for ; Fri, 15 Apr 2022 15:30:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355267AbiDOPdI (ORCPT ); Fri, 15 Apr 2022 11:33:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39410 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355329AbiDOPbv (ORCPT ); Fri, 15 Apr 2022 11:31:51 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E4CC5D64CD; Fri, 15 Apr 2022 08:28:53 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 37219E0016; Fri, 15 Apr 2022 15:28:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036532; 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=yn4DapW7B+b7/Jf58r8UQ+KQTPDQT2kt5oZznM1VWTc=; b=D1P38lGnnMsc0gLE3jEivo9T1KTRnMpeNNK14W+s2nmxqSZvNw6D2+KuBZTNNsTImw/wvN oA03mg3uEumnyjOCf5ps3r4+yZnnRS8Ri2/o6qLaiR5tA2Alu2BrNSmnkBdc3CeG8H4mV6 nxHGoNW4rQNvT4/2U4KnlKwQRs/ZhvONoiK32ZS/Z/IJqRmstICL99ZrxUhyrYAxWG+2Ad jjaQSfG8LYObESBJHCjtD+kwgtY+9fcj1JNp+KfDVfGijXN/oOrB9iZ33dKvZR2ZsB70xq NCFxJ6KgKnswiKJVf44RDitrliXidWqV/tnGxihI/77zkSHifzxJsU8OziLw3A== 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 v4 28/45] media: sun6i-csi: Get mbus code from bridge instead of storing it Date: Fri, 15 Apr 2022 17:27:54 +0200 Message-Id: <20220415152811.636419-29-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 c4e803a38851..e2070353f93f 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; @@ -1076,8 +1072,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); @@ -1109,8 +1103,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 Apr 15 15:27: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: 12815055 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 1BF7CC433FE for ; Fri, 15 Apr 2022 15:30:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345915AbiDOPdB (ORCPT ); Fri, 15 Apr 2022 11:33:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37926 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355249AbiDOPcA (ORCPT ); Fri, 15 Apr 2022 11:32:00 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BCB8CD4C95; Fri, 15 Apr 2022 08:28:54 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 4D1D6E000D; Fri, 15 Apr 2022 15:28:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036533; 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=0g5DnJUWqU1xX4MhkrFEBaH1SIZkGsyug+EenENAgCc=; b=lPTwGQXyhFzplwv1yFQFmKwYVEYlLpRRxC91P6EkGo82ljZR1626jaQur2Gub3zyUacud4 ww0tPJQmozvy08uDklKAGPRVkG48P6R+K2Sah0hqdTgp1/fNtVPdbegwmE9VDb3vPCCgBS g/MJbDeyPEkV5NWai9kR8qf0hWbiOzXjS7QUqjjDf1w0zDtPQOXL1ehzSFCyJH2EZQkrcn OWENWLj6Me44Bto1ShaRypvsG7++VM5m6muufgJQTPbj/b6sZfkrX73j6UrOK1752IjC76 Cv5U87mSKSpo2/Gw7Zcb7k78oT6T8KGoz3dexsRa1SXJ5SXY4UJxTAq8xaPO5w== 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 v4 29/45] media: sun6i-csi: Tidy capture configure code Date: Fri, 15 Apr 2022 17:27:55 +0200 Message-Id: <20220415152811.636419-30-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 e2070353f93f..9488c7c26f13 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_parallel.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 Apr 15 15:27: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: 12815058 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 7FD79C433FE for ; Fri, 15 Apr 2022 15:30:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355239AbiDOPdH (ORCPT ); Fri, 15 Apr 2022 11:33:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38614 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355252AbiDOPcL (ORCPT ); Fri, 15 Apr 2022 11:32:11 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 29B02D4472; Fri, 15 Apr 2022 08:28:55 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 7C40CE0008; Fri, 15 Apr 2022 15:28:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036534; 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=6LxqRCIO3Y6utm9hg/T1+4B+nsXTQdXsUxJWQbb0idE=; b=lb0ZkYVzuV1uzIfdTW69HQQAFTkTKoPd8MQaoKLW4v/HbaBUFf8fU/2sN4e3zXYpcXz5MH jJNkEnIFvbX62DyxJOBjj4PnzSBnAaBq+mIS0DddAsyRUMTVMSrvW1xh4oA4cekInOi2zt pSknZca//4zxaPmUAPWpaJdoASpLJwdxcmeDUpT4+Y36YFwYqtLSMnmyu9e65be7rfGvPQ mVulx5f5hOi+n67jVJAufvUHwRuB2OLIK31dZH3grxuHDS+KNtFoRMqVNTcJ87HPPf5G3+ n4xI1pVhw/w/acsQCCqvuJmn6Sb6FZndjQ9TXlRpzfN2xIk3yGoSsZtajCvbRQ== 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 v4 30/45] media: sun6i-csi: Introduce bridge format structure, list and helper Date: Fri, 15 Apr 2022 17:27:56 +0200 Message-Id: <20220415152811.636419-31-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 0c1e159537a7..79263a421dd2 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 */ @@ -125,8 +222,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; @@ -145,7 +242,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; @@ -161,10 +258,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 5e6448aa522f..cb3b27af4607 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; @@ -48,6 +55,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 Apr 15 15:27: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: 12815062 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 AB1AAC4332F for ; Fri, 15 Apr 2022 15:30:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355302AbiDOPdN (ORCPT ); Fri, 15 Apr 2022 11:33:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38278 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355414AbiDOPce (ORCPT ); Fri, 15 Apr 2022 11:32:34 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7E181D64E8; Fri, 15 Apr 2022 08:28:57 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id AC2D5E0012; Fri, 15 Apr 2022 15:28:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036535; 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=eXuChdGCXB162OwmAXtTZumSjw2hTOB4SNr26U/r1Fg=; b=ZK7q+i/F9fppnl1MkmgROBsjhYCn+L7H4lQ+ANqXQ86pKzBNk+XsvBnQAKsqEVsrbJQOA5 njmTTfVY69pKeJs0NcBIiuNwsRkq4NCqIwoxuyeVaq/joo/q7MJ8aHbMvF1Zh1L+mEGcwu Dre+MivwMj8aKwZ0q5Aa0jbhpA0cjUxfLYczgr3NwY7c+l19toSP3XgjQslfCST0n9F600 5Sxm7SdSPRWqM0ccw27gjhmNd18CBEFVeS3GmwE8KAYRm4hvJqr6ZNu+ELea8SFKM8yjJt h5J1IJESt/stAzIHNeHJDLpXhAjh/WHOSl/28A/F5sZ3riTPRHfanyU3uKDpLg== 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 v4 31/45] media: sun6i-csi: Introduce capture format structure, list and helper Date: Fri, 15 Apr 2022 17:27:57 +0200 Message-Id: <20220415152811.636419-32-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 9488c7c26f13..3d6d856b9213 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 */ @@ -821,8 +947,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; @@ -881,7 +1008,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; } @@ -1153,7 +1280,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 Apr 15 15:27: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: 12815063 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 CF29CC433F5 for ; Fri, 15 Apr 2022 15:30:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355309AbiDOPdP (ORCPT ); Fri, 15 Apr 2022 11:33:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38334 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355412AbiDOPce (ORCPT ); Fri, 15 Apr 2022 11:32:34 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B1247D7626; Fri, 15 Apr 2022 08:28:58 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id E5036E0006; Fri, 15 Apr 2022 15:28:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036536; 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=Q4sbMQINaQ6OcickTMl3kQIseP0Qi98DbinqRuj1iYg=; b=RDL5ypg0KjepmN7C7aSMSnK4PvB3RJRFTymoWgfA4QG8uaKBxz1t+BNZ3X58yhlxleY+Ls pbrLJmLgjKV4HCaQ1ndqdxIsS3WkknRmPuMMLWzV812KyjmoKymfvAgIB5+42cdvPL6Ysi M+jugHRAIK/Mv4Ldlm95f7BAVgZEo5dK4DB94W5fu5vFCRDqNGHnuJjC2VNdrvmt/Ok9fw YXC5+ZRUQPt5L9HApS1NzrxkImmkFPzA4qkd9lhhROy2g/6K4sulC5d+BWShqRGsgtcmhM hsNX6sTcihPetpP+p6Vsw/UXlJoOFXMsvMTfZKJF/RidwMhL/mtVWNBKwSHKhQ== 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 v4 32/45] media: sun6i-csi: Configure registers from format tables Date: Fri, 15 Apr 2022 17:27:58 +0200 Message-Id: <20220415152811.636419-33-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 3d6d856b9213..9ecfb3f35983 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 Apr 15 15:27: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: 12815064 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 D1CDFC433EF for ; Fri, 15 Apr 2022 15:31:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355407AbiDOPdc (ORCPT ); Fri, 15 Apr 2022 11:33:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38372 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355431AbiDOPcg (ORCPT ); Fri, 15 Apr 2022 11:32:36 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CC53FD76CF; Fri, 15 Apr 2022 08:28:59 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 06396E0003; Fri, 15 Apr 2022 15:28:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036538; 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=wyGxn+0aEzq9CJ/mlVX2JBlDUu/U3bTY05TBYj6B3uM=; b=M8JHhFErqrhHuJ5CPQL9RvGw16OBgOrgiytU7eZBrD2/JqoVSf+5j74bcFrvTwQiZORSGf X8tfglt0EAPo9xXXotE9KkbpMBawthVXUJIIJkzM/b/oNfXuajLvIyM/bSYc1tZ2Ew3U9P VQgpVCLtzzyuBISBjQDwfZIs9J2DOMZDMLQCp19WHCpSYtgCwUsS+7S991iQKLD+6XiiWp 9Jv/CN9pKiqQVV7XetMNC2dpC8NWFe4DFzUSNS6K3a5M0EOamJ0vn2QM7fG7Z+yuXcVbxp rOBvErd0aO0MlTEC+7EToWmI6NYIzTDb01qbG0balEXrhrYmS9ndiFvFuuMFNw== 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 v4 33/45] media: sun6i-csi: Introduce format match structure, list and helper Date: Fri, 15 Apr 2022 17:27:59 +0200 Message-Id: <20220415152811.636419-34-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 9ecfb3f35983..f4e12aca43e6 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 Apr 15 15:28: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: 12815065 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 9C4AAC4332F for ; Fri, 15 Apr 2022 15:31:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355430AbiDOPde (ORCPT ); Fri, 15 Apr 2022 11:33:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38692 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355453AbiDOPci (ORCPT ); Fri, 15 Apr 2022 11:32:38 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 87FBFD5EB6; Fri, 15 Apr 2022 08:29:01 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 42113E0007; Fri, 15 Apr 2022 15:28:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036539; 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=GiWEYyjKLcIbwKO7BQiN1/eiKAp7svT9iVHAyVSgwlw=; b=piE6uA+Yduu8J1wK1zfRfnyPwaOkNmica+JnHVoBW2vkvLIfiNbmLwQt+COdJCIzXImPyu toxsiJMtuntWvmgAzBG29EStdIOoxVTGqcF4G7dy55S+PREDNaRjpAm9nwecigvBQS49zQ EcI1PS05NSKpKhGQS3/Gwh2h68/RYQU5Rhs/uVb9ddCHFHN0N/MP0elB+p93eGtm9vVJEg lNjPZ/vzF6P+1b+QOA4TGoJCWeBPbExB96w8iUIc/mdf/Em7ylsuN2DruvwrvRX48UcNzy U/LbB7Cj+MBV8KMnboeTjaac8seYTjJ5NxSKC2eo6Tl0m00m0m5Q5EKP1asFNQ== 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 v4 34/45] media: sun6i-csi: Implement capture link validation with logic Date: Fri, 15 Apr 2022 17:28:00 +0200 Message-Id: <20220415152811.636419-35-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 940d041351d0..0ae10a11373c 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_parallel.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 dd90ffdae5d5..68611c147996 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -51,13 +51,4 @@ struct sun6i_csi_variant { unsigned long clock_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 f4e12aca43e6..b3452ed825ad 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -1140,63 +1140,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 Apr 15 15:28: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: 12815066 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 D3133C433EF for ; Fri, 15 Apr 2022 15:31:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355463AbiDOPds (ORCPT ); Fri, 15 Apr 2022 11:33:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38942 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355457AbiDOPci (ORCPT ); Fri, 15 Apr 2022 11:32:38 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D8838D76E4; Fri, 15 Apr 2022 08:29:01 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 701ADE0015; Fri, 15 Apr 2022 15:28:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036540; 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=7FHQnruHQ5VGh4qmCb+H78ZzzkOR9N2YEfIjwO+nmPc=; b=MGQmF4VSsmCJZKZ1hJg9Jy94mxypz3jtztZ6cZ3DgX+VfFY2HYlSFWMh+vf0nEsaIfZhYs RGCXDrpdwI04QqWMeNPEcc8cP1Ph6sNeeg2tJfrJSy9+CXRXUR0r1qLgFf7EXZCGLDM6Ij 6OALpaf693LCwwlXkdTyQWpeheauX8D7pUmaVI1ae05hA1Z91u8lT6QomVy+ur5P8A0gXJ 8fXBoNQ6lzrOHLCQZrtuUG9kACy43P87raeXcQXZhAl7aHduC3GCeGZglGOMKEzc6bkcDx WTTGnFrCxiF3BuD9BVfPy04Nqn5mha31biy+nT1mRwIZIIxF4DkV9DLghwdqAA== 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 v4 35/45] media: sun6i-csi: Get bridge subdev directly in capture stream ops Date: Fri, 15 Apr 2022 17:28:01 +0200 Message-Id: <20220415152811.636419-36-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 b3452ed825ad..b92f8aa55a92 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 Apr 15 15:28: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: 12815069 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 9779BC433FE for ; Fri, 15 Apr 2022 15:31:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230188AbiDOPeM (ORCPT ); Fri, 15 Apr 2022 11:34:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38584 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355499AbiDOPcr (ORCPT ); Fri, 15 Apr 2022 11:32:47 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 54BA9D790D; Fri, 15 Apr 2022 08:29:02 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 97AD3E0010; Fri, 15 Apr 2022 15:29:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036541; 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=MRU5hlO+G2uUIaBScCxnbEZZ/Wu4I/BXGnhWAjk5qMQ=; b=VY7AR7iR/eTPRAgazk+e9g3HlK4JqF0c97a0jqsFl1Y6nE7WdrFWK8pMxhwxhFZ8BEiJAw HNeYGarAVgNrMTcV5jbwyk4m037zdCWB7WFlQO2s7CSRBXolTWtUx8ympBJp5CNiolTEjM /VniLgMlB+LfnlsqxP2PHuPyavGDOO3G2JfpLnO56SR5A+EKfPXD0OvbZrUN1tto/wcmEd FUig5RM2uHNleaUWwynKLeJJ+dZlgFVJ3NGMfJAIhQCTzIPUrNuEZHapr9vDT8mcMcORcj xhpc6oBaBTmGlIGXrTPdLZUV3/GQ1QKka96381RItsDTqtVpUZJO+DMNIbkaXw== 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 v4 36/45] media: sun6i-csi: Move hardware control to the bridge Date: Fri, 15 Apr 2022 17:28:02 +0200 Message-Id: <20220415152811.636419-37-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 | 227 ++++++++++++++++ .../sunxi/sun6i-csi/sun6i_csi_capture.c | 249 +----------------- .../sunxi/sun6i-csi/sun6i_csi_capture.h | 3 + 3 files changed, 237 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 79263a421dd2..ec3e04353106 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c @@ -174,6 +174,205 @@ 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_parallel.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) @@ -204,6 +403,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; @@ -211,6 +434,10 @@ 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); + + 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 b92f8aa55a92..a6619d083308 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_parallel.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 Apr 15 15:28: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: 12815067 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 5B8B2C433EF for ; Fri, 15 Apr 2022 15:31:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355494AbiDOPeH (ORCPT ); Fri, 15 Apr 2022 11:34:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37646 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355513AbiDOPct (ORCPT ); Fri, 15 Apr 2022 11:32:49 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 89B5CD5546; Fri, 15 Apr 2022 08:29:04 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id B7516E0013; Fri, 15 Apr 2022 15:29:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036543; 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=gGj0QnH8QxZA9mRlqEQryshwhN+v1j41f5zJdRdM9m4=; b=GknlYP5+vG8cneVCfJ35894QrnXKkvkSEa00P2ZF9hmjJYA0oYV04WTLcdVoBDWqTWl6sn 6oFGWB3nPxClOOSnFuj2ptQvZ52BS+mp2nBwukWelOtiYvAC+syTTOic+96ALSoKjB2alJ ClPsJMCgPubTPWaJ4XRZqqJtbJoJKwK7Rd1dlFdcm6Hx2tvnKvhhMtiyAvP9C8Ntbdq+KI 7bHYb8vSZsLXpM4Dl5fYLoLnHlta0/3EDd4zjOVANIVIeiku/zYJMbSo26Jvc+0R6bwslg 5ObhOWS97I+DEVKkFDGR3Nn+5CL6L+mZVYW08RSsDScRUNzzF6DgeNYNTIqK9Q== 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 v4 37/45] media: sun6i-csi: Rename the capture video device to sun6i-csi-capture Date: Fri, 15 Apr 2022 17:28:03 +0200 Message-Id: <20220415152811.636419-38-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- 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 a6619d083308..c3b1e1411da4 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -1027,7 +1027,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 Apr 15 15:28:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Kocialkowski X-Patchwork-Id: 12815068 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 E5237C433F5 for ; Fri, 15 Apr 2022 15:31:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S244070AbiDOPeK (ORCPT ); Fri, 15 Apr 2022 11:34:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41350 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355531AbiDOPcw (ORCPT ); Fri, 15 Apr 2022 11:32:52 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BA938D5566; Fri, 15 Apr 2022 08:29:05 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 1B724E0014; Fri, 15 Apr 2022 15:29:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036544; 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=gq6c5C3mzU2DdVbLXo2EbQMC2rnxwdZ/6rLEd5OE3vE=; b=hCRuG3/KTx//R38cF4ySmB+RINazrLwh5vinIAY59FaaHh9BzjfOhSUBZS0hCsNfaB0xby IeY2q/ttl4M6QZgxQmMSCbSQLmVuuzszQaCklwLghiqZVn9+1IK4QmFtI1JIdTKxmuv2jr wg7qViQ7WBn9hK1jGO7lcFzy5syKsrx7FizQcxy1aj2fC1HwcXD495cHtnwStny6mvtb1q Jg95BdBKHyQJBKGvuCA7voQ5NijapAgo/bDxXOy+iykn6dDMge3MPzMw09hcFhENOfBBCg fVxNx+ekxE3/0vGnnCXVUYF9BBjcBOCtnmsjQ/HwediH50p8XY8tJjYgaZBaow== 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 v4 38/45] media: sun6i-csi: Cleanup headers and includes, update copyright lines Date: Fri, 15 Apr 2022 17:28:04 +0200 Message-Id: <20220415152811.636419-39-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 0ae10a11373c..43b6557b3207 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 */ @@ -390,4 +387,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 68611c147996..1aeaef84abba 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" @@ -51,4 +51,4 @@ struct sun6i_csi_variant { unsigned long clock_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 c3b1e1411da4..f1581b877819 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 Apr 15 15:28: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: 12815070 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 2E59BC433F5 for ; Fri, 15 Apr 2022 15:31:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355510AbiDOPeV (ORCPT ); Fri, 15 Apr 2022 11:34:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38334 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355255AbiDOPdH (ORCPT ); Fri, 15 Apr 2022 11:33:07 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5921BD7921; Fri, 15 Apr 2022 08:29:07 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 62181E000B; Fri, 15 Apr 2022 15:29:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036545; 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=lmbm3uu6Ak9ybLK1C+cGzGH40257deustHb6NnF5VoM=; b=Gs0wFkW9nstaRhLKrH0BZCZ7AvoJhheTqX63akGh1+Uy/OIxnW0ES1OCDVZvCeOIBnIc0p xakPfADhA4rp27x1sObZiUrAgjem+E1HTash1TmDWlwfR9OgA36GfHR8sThJFrF8oLDAsv W2Ro6ARel58rIrK7r1rMZ41taqILSd2dmHcx51MjlnZQK6pAt904P+JysVf7CxHvyk/7yh UqAB92Un1kwka4qGjjfjElfP/9hXXDOiI3p14WQpzQLDcF2Qu2rbb9dekgaJHxim/Khb1k LBAbAMlCNuIKeb0XC90h4duF965lGwZuiQyvr8JCCe8GkXcvTDupCOflUQiIfw== 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 v4 39/45] media: sun6i-csi: Add support for MIPI CSI-2 to the bridge code Date: Fri, 15 Apr 2022 17:28:05 +0200 Message-Id: <20220415152811.636419-40-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 1 + .../sunxi/sun6i-csi/sun6i_csi_bridge.c | 46 +++++++++++++++++-- .../sunxi/sun6i-csi/sun6i_csi_bridge.h | 1 + 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 1aeaef84abba..6aa83dd11684 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 ec3e04353106..27289d904d5c 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; @@ -367,9 +386,16 @@ static void sun6i_csi_bridge_configure_format(struct sun6i_csi_device *csi_dev) regmap_write(regmap, SUN6I_CSI_CH_CFG_REG, value); } -static void sun6i_csi_bridge_configure(struct sun6i_csi_device *csi_dev) +static void sun6i_csi_bridge_configure(struct sun6i_csi_device *csi_dev, + struct sun6i_csi_bridge_source *source) { - sun6i_csi_bridge_configure_interface(csi_dev); + struct sun6i_csi_bridge *bridge = &csi_dev->bridge; + + if (source == &bridge->source_parallel) + sun6i_csi_bridge_configure_parallel(csi_dev); + else + sun6i_csi_bridge_configure_mipi_csi2(csi_dev); + sun6i_csi_bridge_configure_format(csi_dev); } @@ -381,6 +407,7 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on) struct sun6i_csi_bridge *bridge = &csi_dev->bridge; struct media_entity *bridge_entity = &bridge->subdev.entity; struct device *dev = csi_dev->dev; + struct sun6i_csi_bridge_source *source; struct v4l2_subdev *source_subdev; struct media_link *link; /* Initialize to 0 to use both in disable label (ret != 0) and off. */ @@ -398,6 +425,11 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on) source_subdev = media_entity_to_v4l2_subdev(link->source->entity); + if (source_subdev == bridge->source_parallel.subdev) + source = &bridge->source_parallel; + else + source = &bridge->source_mipi_csi2; + if (!on) { v4l2_subdev_call(source_subdev, video, s_stream, 0); goto disable; @@ -415,7 +447,7 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on) /* Configure */ - sun6i_csi_bridge_configure(csi_dev); + sun6i_csi_bridge_configure(csi_dev, source); sun6i_csi_capture_configure(csi_dev); /* State Update */ @@ -607,6 +639,7 @@ sun6i_csi_bridge_notifier_bound(struct v4l2_async_notifier *notifier, 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 *bridge = &csi_dev->bridge; struct sun6i_csi_bridge_source *source = bridge_async_subdev->source; bool enabled; @@ -614,6 +647,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; } @@ -760,6 +796,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 cb3b27af4607..ee592a14b9c5 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; }; /* Helpers */ From patchwork Fri Apr 15 15:28: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: 12815076 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 4A54FC433FE for ; Fri, 15 Apr 2022 15:32:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355280AbiDOPef (ORCPT ); Fri, 15 Apr 2022 11:34:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38378 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355369AbiDOPda (ORCPT ); Fri, 15 Apr 2022 11:33:30 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 99597D8F49; Fri, 15 Apr 2022 08:29:08 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id AB7DBE000C; Fri, 15 Apr 2022 15:29:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036546; 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=0aL1gd4kAuc3u2gUbOpzUUJFI/u1xg+hRYW41JoQJHA=; b=VRNTWd0FbZN8S3b+Hi+l50A1iGwIWAHrLeGC31ZQySA6P7ZN/BQVyb5RssgQCR+Yidv141 j2cTq4A5YVPZnwL2T07cpNsLeYi48ivU17pPaUkiXIKxxoJ06MvEGxnx7IGgPiEg2nDSYc p/dmigViuvELgIKaeR0qz0TnBRxT3yXAO8cEs2zNUGUiIj2ihOtuTNJp2R//YUgGVR1oQj BeGu2IbV266z9VHGtPQFmpFyPlgOftQtZRn7B1/FlX8H4YxSiyFefL3xsnnfWuzAl++lUL FULFB3sG7AK+PL1vYpjzLq70aE0ArmroI2VA/scr8jOr+h0zAM3z9oC6BNYM8A== 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 v4 40/45] media: sun6i-csi: Only configure capture when streaming Date: Fri, 15 Apr 2022 17:28:06 +0200 Message-Id: <20220415152811.636419-41-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- .../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 27289d904d5c..8e9eded0df28 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); @@ -406,6 +410,7 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on) struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev); struct sun6i_csi_bridge *bridge = &csi_dev->bridge; struct media_entity *bridge_entity = &bridge->subdev.entity; + bool capture_streaming = csi_dev->capture.state.streaming; struct device *dev = csi_dev->dev; struct sun6i_csi_bridge_source *source; struct v4l2_subdev *source_subdev; @@ -448,15 +453,20 @@ static int sun6i_csi_bridge_s_stream(struct v4l2_subdev *subdev, int on) /* Configure */ sun6i_csi_bridge_configure(csi_dev, source); - 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); @@ -466,7 +476,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); pm_runtime_put(dev); 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 f1581b877819..17145ce53395 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: @@ -634,11 +638,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 Apr 15 15:28: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: 12815073 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 3E07DC433F5 for ; Fri, 15 Apr 2022 15:32:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355402AbiDOPe1 (ORCPT ); Fri, 15 Apr 2022 11:34:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38372 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355367AbiDOPda (ORCPT ); Fri, 15 Apr 2022 11:33:30 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AC7D1D8F54; Fri, 15 Apr 2022 08:29:09 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id D38A1E0008; Fri, 15 Apr 2022 15:29:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036547; 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=a4cnzWuTGffjryQBqgGBFOHFWDCSqhQFuFNHTBbesc8=; b=XCVcJmrQqhxE4TzSjVzyggVUK/fFX8TRrpguo+t7PW1LjswkIxkA0cRKrw7LxabH5vqx7I W63h81hAagaar/3XXMrrmRjndAwFXluaYP0X4Bgbx9A7az5FSb8sCB8bMRMxgr+pM6YvU7 +NPw+kAmxS+zbBDGV7k76u9OERUb+2V5AGQRvc7ZnIxY6S69lWjdxfYMJL58Icb+M5TPXM Z9RrEsF34TOJ2uCJiEG4sybHHU9mKY1lx9HGJkHYZn8WRTULXpMck882bIxngGJJgPakNS FxtV34AdpZBhAqgz1ymHtRqVuGhszOaHLCdPZKR0yvWOHTL1s5B6Wmpr9Ihgfw== 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 v4 41/45] media: sun6i-csi: Add extra checks to the interrupt routine Date: Fri, 15 Apr 2022 17:28:07 +0200 Message-Id: <20220415152811.636419-42-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- 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 43b6557b3207..3963a88a2e0b 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_interrupt(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_interrupt(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 Apr 15 15:28: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: 12815074 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 BD596C433F5 for ; Fri, 15 Apr 2022 15:32:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355207AbiDOPe3 (ORCPT ); Fri, 15 Apr 2022 11:34:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38688 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355418AbiDOPdc (ORCPT ); Fri, 15 Apr 2022 11:33:32 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 83293D76D7; Fri, 15 Apr 2022 08:29:10 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id E8F3BE000E; Fri, 15 Apr 2022 15:29:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036549; 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=kIKrZdtsil/MNpFBBasiC6gNT6MWi1CosOG1DDN4qfM=; b=Hnr18tRXaOiYnZc1/S5oTzPVF6QFWXL2Tjv+p32i+C811ZMhn/ssOLlE05jjE9wUoUjZ+/ fO5p0j/+zSKSvgkEoOykg16Y1/I8pI8aa2T8iqA5oOIv2cqi8bcSl6mkPBDLKPEjOhUpgx C30DEAbGoKGBNqgncfXeyS+qv16npf1hIMaYR+kyE3uVmYTqWS3esPOvovejvlpsoq3Stu bCgqdl+cr/VMx02iWbCRZcfM7RiqzIA9QfKAZnXkrOrLab3ZpaXhsWWXRaVnw+qteYD4Ns DAX7dyMenkHlgenxww4LTquNsq9+KepmSlIdZnWgJ8De0QavHtq0/Jt59ETSKg== 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 v4 42/45] media: sun6i-csi: Request a shared interrupt Date: Fri, 15 Apr 2022 17:28:08 +0200 Message-Id: <20220415152811.636419-43-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 Acked-by: Jernej Skrabec --- 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 3963a88a2e0b..a88deb8ba1e7 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -264,8 +264,8 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, goto error_clock_rate_exclusive; } - ret = devm_request_irq(dev, irq, sun6i_csi_interrupt, 0, SUN6I_CSI_NAME, - csi_dev); + ret = devm_request_irq(dev, irq, sun6i_csi_interrupt, IRQF_SHARED, + SUN6I_CSI_NAME, csi_dev); if (ret) { dev_err(dev, "failed to request interrupt\n"); goto error_clock_rate_exclusive; From patchwork Fri Apr 15 15:28: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: 12815071 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 895C1C433FE for ; Fri, 15 Apr 2022 15:31:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355285AbiDOPeX (ORCPT ); Fri, 15 Apr 2022 11:34:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38294 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355562AbiDOPds (ORCPT ); Fri, 15 Apr 2022 11:33:48 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [IPv6:2001:4b98:dc4:8::224]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AC4B3D5E8C; Fri, 15 Apr 2022 08:29:11 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 1C01BE0009; Fri, 15 Apr 2022 15:29:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036550; 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=eJhdnVljXNxVEUMy4in6EAVIykPxuz30jn1QuT2PjaY=; b=Zk7yFys2c2BJ9az9iLbgPiy+++XOJFjJ9avanOahl/MwOs13EJRsry5ULsFMWtj0sFPkG3 +X9FEp5q09ETZvrFJaR9tm7kh+Y1fkNjfdkfnvTKYVhhiiCCf3crFCA4lKRbkm6AgjWLJJ zNhciEKHvb1qr1qr74A1QNf97sTEHc39Q9XglU1hC1MSyCLlxod8WbOEfC/trL/AcFIKBy ptrTgc9JWO+r8m3gkqwrpyHx7oAfaSmxcnPi3lsGi5Uxxbe73vy3Y/9aohqC9QsYgl8MFj bPE7bE3/gTQx/Z2QXDRgkCRFbkSl+Cwmvc4edQmgBg5wUzKvV6hcA4BPdjnSOQ== 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 v4 43/45] media: sun6i-csi: Detect the availability of the ISP Date: Fri, 15 Apr 2022 17:28:09 +0200 Message-Id: <20220415152811.636419-44-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 a88deb8ba1e7..f185cbd113c7 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 = { @@ -306,6 +335,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 6aa83dd11684..9b105c341047 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 { @@ -46,6 +47,8 @@ struct sun6i_csi_device { struct clk *clock_mod; struct clk *clock_ram; struct reset_control *reset; + + bool isp_available; }; struct sun6i_csi_variant { From patchwork Fri Apr 15 15:28: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: 12815072 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 185FAC433EF for ; Fri, 15 Apr 2022 15:32:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1355428AbiDOPeZ (ORCPT ); Fri, 15 Apr 2022 11:34:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39214 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344979AbiDOPeE (ORCPT ); Fri, 15 Apr 2022 11:34:04 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B455ED59A3; Fri, 15 Apr 2022 08:29:12 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 49DE5E0004; Fri, 15 Apr 2022 15:29:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036551; 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=9JhQiospt201/YYwtRxbWRBE1cQns5t2tLJKR9dIwXM=; b=YlUd25nnIxFyArmxNLK7pBjUjxbgFSUtbjbwOGQ/Q6sosuvzU1shM2dbAnWiIkx6pkmsLv VILWlIE7FS1wJyN5RuFJ1A7tmtVQHVO99s9k/tSKcnZq9fd+jYbb5KApFa+jUGv/cxWRiu kR2AtCPy+aDSeCsJ1ot3GtRU/s3x9t63pGtzEuhX1rAeC7VjcAbRdETtOXOAeNEszDZ269 EKuzTKviYmjBilESodN8yOI0BIncMJeuyJKq/INn9zj148hUOICHyR0AEFGgGOPQH18o0W /9uWyvQ13imgbB9f10XxGxrUNu4006aPHUBeezEFunwVLBnph6ODAjpe9YpD/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 v4 44/45] media: sun6i-csi: Add support for hooking to the isp devices Date: Fri, 15 Apr 2022 17:28:10 +0200 Message-Id: <20220415152811.636419-45-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 | 32 +++++++++++-- .../sunxi/sun6i-csi/sun6i_csi_capture.c | 19 ++++++-- .../sunxi/sun6i-csi/sun6i_csi_capture.h | 1 + 5 files changed, 89 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 f185cbd113c7..c3fbd0d7a2d9 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: @@ -339,17 +354,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; @@ -357,7 +382,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); @@ -371,7 +397,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 9b105c341047..afa96488b94c 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; @@ -55,4 +57,9 @@ struct sun6i_csi_variant { unsigned long clock_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 8e9eded0df28..9624c3f683ee 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c @@ -654,6 +654,7 @@ sun6i_csi_bridge_notifier_bound(struct v4l2_async_notifier *notifier, struct sun6i_csi_bridge *bridge = &csi_dev->bridge; struct sun6i_csi_bridge_source *source = bridge_async_subdev->source; bool enabled; + int ret; switch (source->endpoint.base.port) { case SUN6I_CSI_PORT_PARALLEL: @@ -668,6 +669,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); } @@ -680,6 +691,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); } @@ -753,7 +767,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; @@ -794,7 +808,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; @@ -811,7 +829,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); @@ -823,7 +844,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 17145ce53395..4a48ab178437 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; @@ -893,7 +893,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; @@ -975,7 +975,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; @@ -984,6 +984,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); @@ -1062,6 +1066,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) { @@ -1072,6 +1077,8 @@ int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev) goto error_video_device; } + state->setup = true; + return 0; error_video_device: @@ -1090,7 +1097,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 Apr 15 15:28: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: 12815075 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 7B016C433EF for ; Fri, 15 Apr 2022 15:32:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344499AbiDOPed (ORCPT ); Fri, 15 Apr 2022 11:34:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38584 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1355479AbiDOPeG (ORCPT ); Fri, 15 Apr 2022 11:34:06 -0400 Received: from relay4-d.mail.gandi.net (relay4-d.mail.gandi.net [217.70.183.196]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A7AD4D95D9; Fri, 15 Apr 2022 08:29:13 -0700 (PDT) Received: (Authenticated sender: paul.kocialkowski@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id 6DCDEE0006; Fri, 15 Apr 2022 15:29:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1650036552; 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=m5FdMa9Ygm39RABeS0v8oIUERHMNnibQFLc9p80cNvQ=; b=LQLPzVMNrWpvvTAVukzVQrtek8eepL8FW/yeKL5lk7qMMq+Mp4iTeEC42Zj5otXSnZaq87 KEv+GO8qdrpklfqsmeoKf62wInjlJYBAmUTWLernGVj2KLmcPxr6ZtS8lYZhj7SVTZT398 JQX1jAPc2syj8SShyylUWAtyRRiGYp2l8ZHP0jqbx6pD1IRhp+bR4TK1CCofhWz6VhcoR8 jf1fynNpzeb+r/uFeJri2+PZrLKgcBF3V/pt86Vn5NCJrz7188XukBka+wSqpmA5Kg23v8 vKG4aAVMo9wFM3MjpI09a6ARpMLuvyJu5qUq1MbYe1UaWmtj2YNdehYoXK66yg== 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 v4 45/45] MAINTAINERS: Add myself as sun6i-csi maintainer and rename/move entry Date: Fri, 15 Apr 2022 17:28:11 +0200 Message-Id: <20220415152811.636419-46-paul.kocialkowski@bootlin.com> X-Mailer: git-send-email 2.35.2 In-Reply-To: <20220415152811.636419-1-paul.kocialkowski@bootlin.com> References: <20220415152811.636419-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 0c7a3c792837..43f456982ecc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -761,6 +761,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 @@ -5232,14 +5241,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