From patchwork Sun Feb 11 19:03:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mehdi Djait X-Patchwork-Id: 199506 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:50ea:b0:106:860b:bbdd with SMTP id r10csp2064742dyd; Sun, 11 Feb 2024 11:04:19 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCXYT2MyaB6kbAKGx5ns3rX6201GUlgiYoJKky01YXszPanKFOhiSAcc7Cw7gBGVDkIr/MWdi1po/Ekb1tq5PGDI2vJ/Ig== X-Google-Smtp-Source: AGHT+IFTL5lPt8WUkNLCbRcBMXOjT4+aoJt2lZj+zrRw7BHwH8CjGMQJU86tUyn+mLmUcZdbVzzb X-Received: by 2002:a17:902:ec82:b0:1d9:9e4f:c0c8 with SMTP id x2-20020a170902ec8200b001d99e4fc0c8mr7431092plg.18.1707678259447; Sun, 11 Feb 2024 11:04:19 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1707678259; cv=pass; d=google.com; s=arc-20160816; b=yMgm4Yr37TgV1QfEHlm6vYKNJtAcTzGDv+Ayn+0ZHwOgpUurlbFWZg8NgL2RRaMozm WW27uAJfZzKMAC54Jf2T3RmdikrW6CpyzMPkFYYuzFR/y9k1UvbVMK4qbvkNibk4YGju rJJ6OuO96BFYV4OoGl/9cnOPlydKmATJBeZGdEdVNfOyWtMsKBg3R06OtgjWWZqq5pWL /6x0nGAY7Lw4shqcWfU+gscu6hzaGiQCEbV6E59BAx/ld3BZkAJi3XUqT6Q/QZ2nEOr8 Fjr6CPuxx5i8im+KonWk1/M1WZnF6VLq/I49giX71kJ73KGlEe3W52qYNiqV0tK4MBdi RuwQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=sKk0NSJH0NwGKwQItSQOBruTltCGsF+0CI7v15bHwUA=; fh=VR2941Y/BLZmxEvPMb1w6FHcV5oYIYRl3eI6fzraj6s=; b=Gecyvr3rMkMSQvATLDIJhV7j210gE5cZyjLxyR4zPyvmOKZ1XrATLQPlwBWJS5mCQa ApcbYtunC6Gp4Z1uL8r4T5O92LcVoqrBVdMQEb6J1CrRhvXJq7HnsdYzhzipFAcQbN22 QXeyIHs7dKc/3gIBCjQ0SA1oinR/PAmG02MMnROhAw3316FTBpaXSBDWkdNQNwbPgbX/ MXUclDuPuBqDqZBJU8CxX9qmzpshhLIHLSFOFZ/ik95RmPsMvS3FIpzoNoX+S5WDftx3 GgtC47xy2o/lvzJ5LYh6xnTtzormkThqTUwSz4dnspzEstHsh490uVOw1Y1zQu5jXzOm SLUg==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=BtWMuXfj; arc=pass (i=1 spf=pass spfdomain=gmail.com dkim=pass dkdomain=gmail.com dmarc=pass fromdomain=gmail.com); spf=pass (google.com: domain of linux-kernel+bounces-60919-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.48.161 as permitted sender) smtp.mailfrom="linux-kernel+bounces-60919-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com X-Forwarded-Encrypted: i=2; AJvYcCVa4LZi1XuzrlCb9rQ+eJM/Y66cfDQuadNVm78mCdqGNUrHbKWOtd+A13hWG5dZTuXIIx5o4bLe7XXabVMqKRrDdstEow== Received: from sy.mirrors.kernel.org (sy.mirrors.kernel.org. [147.75.48.161]) by mx.google.com with ESMTPS id q16-20020a170902eb9000b001d75054db45si5300653plg.98.2024.02.11.11.04.19 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 11 Feb 2024 11:04:19 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-60919-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.48.161 as permitted sender) client-ip=147.75.48.161; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=BtWMuXfj; arc=pass (i=1 spf=pass spfdomain=gmail.com dkim=pass dkdomain=gmail.com dmarc=pass fromdomain=gmail.com); spf=pass (google.com: domain of linux-kernel+bounces-60919-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.48.161 as permitted sender) smtp.mailfrom="linux-kernel+bounces-60919-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sy.mirrors.kernel.org (Postfix) with ESMTPS id 51242B219CA for ; Sun, 11 Feb 2024 19:04:18 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 2C9605DF3C; Sun, 11 Feb 2024 19:03:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="BtWMuXfj" Received: from mail-ej1-f44.google.com (mail-ej1-f44.google.com [209.85.218.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1F5B95A4FF; Sun, 11 Feb 2024 19:03:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707678221; cv=none; b=mcLZu7Zp4uz+y7vWjuGyEcMgMBns9NaxY3yyyl74lbP5yTfxPxwqVn6zLsEy++/r1DBX8ah9TnZSnieSFN3D98RWZFWwtjlSuGoiCCcOLooLfTUUzVoi2PYr6/zUk3K7Z8SVMbEuUDKl19BRlaJkYgZ0ggK5uzdQztnerMQ5L8M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707678221; c=relaxed/simple; bh=tpeWXxPW9y0R5ANl3dpUfOq3RGhBakzINSXMqQQKvkc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=qQh3JN4Pwb0bUuHTR+etInA0YfrSfs/DaYPZITt7MKGZK1gvJavQCWgqYO4oV5ByREe55GZ3dK1evxJ98/aR94NPnVw298D1mlakLSbvVTKKWcsWJJhwES2WKiHCh8QoxA0T2XvlQZRI2V9l29mJUBlObs1147ac0RO19WyeRBw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=BtWMuXfj; arc=none smtp.client-ip=209.85.218.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ej1-f44.google.com with SMTP id a640c23a62f3a-a271a28aeb4so315100466b.2; Sun, 11 Feb 2024 11:03:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1707678218; x=1708283018; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=sKk0NSJH0NwGKwQItSQOBruTltCGsF+0CI7v15bHwUA=; b=BtWMuXfjBk5Sn/3t3U61ECU8vh7NMOpoxDEhbN0LLo2zIiAldHCSeJh0tOQxSGSuLW 7GoD2CUscNa7U86hPn3emX63EX02+mcnnyvUkeSXk45awlQgHFZu1Y2N3NVOfg4/NljF B9gIrUse5RnKXezkHItcs16asIvPeYSULxQxokWvV7GTUM+onaPRmzCQaQliUd3Braeo 0nVXl7bKrGlh/oCtGEB+OF1SW9WwHt+hfJcLXj07fYlnRe1aVcHtgLrQ1XqiPLlJ+a/R JgBgeSchLyubHBPEa1WYsnaWQ5CtrUQL1bCg1EH5dgjmg1upS1ikyb+1ljzV9Q8h0wj+ KUqQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1707678218; x=1708283018; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=sKk0NSJH0NwGKwQItSQOBruTltCGsF+0CI7v15bHwUA=; b=P/5cSqFfNx3oc7q1DkVUIJpHTpOVrNrjM6jbs6y7cvKO0kAt6zbqsAGIO0N5P+LUk2 hu29v6QVwuixnd/0Y7VuSQ/BZBAxZAEHkkGAnLX0wqDNIZt6MzYRMm7OQgWQ8c42M+Kf 8d0GLvdMb61XEXphKR8l3+aJOsbKh6HgmhdjbEL9FtnlvIqI2JvyX0rCWsmlufgnVr0j /xvgLLcs+IdrFqnoBr6W22UFkz2HqQx4/85JgeTQ6gQkZupYmMHkIiywPaalWQ9aOblJ ec7+mkfYoJyILbY++7y+d02dPjME3DutWHRbc3zFpahPpLlWsqmwFXQDoMcbPm8ZAXak kjUg== X-Forwarded-Encrypted: i=1; AJvYcCV6WoKblBjtCwJL9MbZba+3rk4w79H58GoktWMkcKFEmm0ugs0VLA8DHUBWrZpNl0WnRfFVMmrAtQ8s+319UkGW/buQzLVG3uyAEY5Uh14rBjNk6zi94Gq9x6tm4Cmn8xR3uAw2LTJVow== X-Gm-Message-State: AOJu0YyTbKcmHs8SSvHLSG3ylgBXC5l7CAU/jy/RsUp0vRupDeZfLwwc ToL1r3eleqOGYDLtYskSGlOx7Cvcg6g+lzZFMr9eNh7pfBtfor8Y X-Received: by 2002:a17:906:fad0:b0:a38:4f2b:8591 with SMTP id lu16-20020a170906fad000b00a384f2b8591mr3740023ejb.69.1707678218261; Sun, 11 Feb 2024 11:03:38 -0800 (PST) X-Forwarded-Encrypted: i=1; AJvYcCV9xUW1N1zNSlG3bvGQZfSlWU8yACAGpIwj5Nbwhaxe9ZQM4cO9Uoguf1SgKM55eslVsWH5u7G98hSd9tQwE4bjAdVe0XajYTif93t4qgBywiN0iWvOVHzFd72TmAss3zTrcjo6N6lJLcGAapBo1kmgY5mKVBQ5v07P2TWcrLPfqqtEfJQQ/Qq7KN8xXr/vEUpMIqwYmomLqni0osXv8o5I+5M43deFwm4SXalaUSWNAhAK9w7945KoL/D6F0RQUcV6uSKq+jnYdYR8mLG5Lezob3S40z+yUHU9GIYXCP1vDZ6nV3uxnehC0lD4LMKXKjrOroJk7Uq2BcTsa/phFTWxPSwAYSk7TVDjfYeeXHJKLzBSfZDrIFE4vtyEYg9w9Y2xrVQUKFASiebgsOO1aUI7KPQRtYsFUiP0nhOa7Fq6r1o5JycIzmRjQTxsgYsrUM4cYCuo6C5lbZLMJpEe3NrirseQ9YgGHSeX+swIkoQsu7QA54jSGlPruQy0G0s7LIjqBQ3SacXbMK6ZQc0GBnIKgkwfsjEYEf8+cDe1xSyK5yBtYhxH88qlluCyn/5qJf0hdRjJyHbMVI/frGIjElmZ8zI4ApKREFOztM6cXcyC7Q2na8fzBbdeYOustMhjnxqQ4PEXEqzzGLrZ Received: from localhost.localdomain ([2a02:8109:aa27:2d00::2d2b]) by smtp.gmail.com with ESMTPSA id ps7-20020a170906bf4700b00a3c5fa1052csm1207400ejb.138.2024.02.11.11.03.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 11 Feb 2024 11:03:37 -0800 (PST) From: Mehdi Djait To: mchehab@kernel.org, heiko@sntech.de, hverkuil-cisco@xs4all.nl, krzysztof.kozlowski+dt@linaro.org, robh+dt@kernel.org, conor+dt@kernel.org Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, alexandre.belloni@bootlin.com, maxime.chevallier@bootlin.com, paul.kocialkowski@bootlin.com, michael.riesch@wolfvision.net, laurent.pinchart@ideasonboard.com, Mehdi Djait , Mehdi Djait , Conor Dooley Subject: [RESEND Patch v13 1/3] media: dt-bindings: media: add bindings for Rockchip CIF Date: Sun, 11 Feb 2024 20:03:30 +0100 Message-ID: <13deb8c5cb58e08c1b47decd112b51e8e0b6c4dc.1707677804.git.mehdi.djait.k@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1790630438518561292 X-GMAIL-MSGID: 1790630438518561292 From: Mehdi Djait Add a documentation for the Rockchip Camera Interface binding. Reviewed-by: Conor Dooley Reviewed-by: Michael Riesch Signed-off-by: Mehdi Djait Signed-off-by: Mehdi Djait --- .../bindings/media/rockchip,px30-vip.yaml | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/rockchip,px30-vip.yaml diff --git a/Documentation/devicetree/bindings/media/rockchip,px30-vip.yaml b/Documentation/devicetree/bindings/media/rockchip,px30-vip.yaml new file mode 100644 index 000000000000..6af4a9b6774a --- /dev/null +++ b/Documentation/devicetree/bindings/media/rockchip,px30-vip.yaml @@ -0,0 +1,123 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/rockchip,px30-vip.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip Camera Interface (CIF) + +maintainers: + - Mehdi Djait + +description: + CIF is a camera interface present on some Rockchip SoCs. It receives the data + from Camera sensor or CCIR656 encoder and transfers it into system main memory + by AXI bus. + +properties: + compatible: + const: rockchip,px30-vip + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: ACLK + - description: HCLK + - description: PCLK + + clock-names: + items: + - const: aclk + - const: hclk + - const: pclk + + resets: + items: + - description: AXI + - description: AHB + - description: PCLK IN + + reset-names: + items: + - const: axi + - const: ahb + - const: pclkin + + power-domains: + maxItems: 1 + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + description: input port on the parallel interface + + properties: + endpoint: + $ref: video-interfaces.yaml# + unevaluatedProperties: false + + properties: + bus-type: + enum: [5, 6] + + required: + - bus-type + + required: + - port@0 + +required: + - compatible + - reg + - interrupts + - clocks + - ports + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + parent { + #address-cells = <2>; + #size-cells = <2>; + + video-capture@ff490000 { + compatible = "rockchip,px30-vip"; + reg = <0x0 0xff490000 0x0 0x200>; + interrupts = ; + clocks = <&cru ACLK_CIF>, <&cru HCLK_CIF>, <&cru PCLK_CIF>; + clock-names = "aclk", "hclk", "pclk"; + power-domains = <&power PX30_PD_VI>; + resets = <&cru SRST_CIF_A>, <&cru SRST_CIF_H>, <&cru SRST_CIF_PCLKIN>; + reset-names = "axi", "ahb", "pclkin"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + cif_in: endpoint { + remote-endpoint = <&tw9900_out>; + bus-type = ; + }; + }; + }; + }; + }; +... From patchwork Sun Feb 11 19:03:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mehdi Djait X-Patchwork-Id: 199508 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:50ea:b0:106:860b:bbdd with SMTP id r10csp2065077dyd; Sun, 11 Feb 2024 11:04:59 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCUKe2+66HsHl16EOXqpxJ9sSB3zrROXxDlidUsf1Pky5cYR1W8L1lAWRGM1EoFV9F1Zd4lZy+449t+ib6K1EwehTdI77A== X-Google-Smtp-Source: AGHT+IF4tKN4Yy4tJX51CunMLUGtNWe5f+ptuEG9eFmj5botjxpdUOEFD7urx7X/UKJKVEK+qZaY X-Received: by 2002:a05:6402:3118:b0:561:8452:3634 with SMTP id dc24-20020a056402311800b0056184523634mr1980926edb.36.1707678299327; Sun, 11 Feb 2024 11:04:59 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1707678299; cv=pass; d=google.com; s=arc-20160816; b=qQzGJZSujsgaR1bxKdPDBUeMBCx4JsICrKMK6JWOk6m+jq5ycGR11YxZvtCMw05x2f k4QY9+hoSxYxZsixcHYxy5j432GQU9LYW2vjVtdG/g9GXTm6YXj3cDBO5eYOy5b6Q414 fMGsFa5rSijStDznfbSILB7+AfaO0aHRWPg/neG6WGy4zna4/1aUPM7evaDiTp6jIyH+ 6ZyCAhriPySyekpHdOui6F/8wgr+AtB9q99rd4uY2TVW0B35vmueIbpW/pQkCjPbbeA+ 0y0kPQ9QrB0lpevC28ZGK9q81gPxgac6zC9/plXW7nk95c6zIloA5QytzKC5JhgWxdYW Z4hw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=6UELQfcO6ackvRjvkMbp0zi8LAe3DQMmzMATvXyQ8MY=; fh=nG3/O3dxMKKEHP/hYefZ0fF8Qa3Gd//I6gEWiRPhu3A=; b=uJoYp3we6c8TMcR5E4EmBp4gZ9mI5rE3HTP9/Z6eeY5PiiSh8omzGSs2UjoVOiKDuJ iK81c4IUMqtIp4DQ9zVue5utBrmc7TffLOe5s8ZrsOiekpmQ3S2HSoGmGOO5WJk3ORm1 1bhZrJMxGD0cPfUq7UaCaGrnE43iSr2ZVu9m4iD2F/WdNqFSwMb9W+oVAaliBCSiazRS HPvssLvCcrZJmm6YtqYDIdzn2K+2DniiHLy7mrsLKUUC6g5GupaU6feXlAwY/JcEA/zE uETKUvlm1A0vN+psJKKK+DcftrxfYy30VB2rpbZrJDhyC/1HBG/kGHX+z94SLdcSMkh3 F/Wg==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=a4uoH19M; arc=pass (i=1 spf=pass spfdomain=gmail.com dkim=pass dkdomain=gmail.com dmarc=pass fromdomain=gmail.com); spf=pass (google.com: domain of linux-kernel+bounces-60920-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-60920-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com X-Forwarded-Encrypted: i=2; AJvYcCXufLsPBXZ4PO2KRzQzBYyAtbelR97tpReOZAURweOG79etsyCSEDw13bX/hSbeUquFNIkVhc+CRqnAgufjI3/DV5LhrA== Received: from am.mirrors.kernel.org (am.mirrors.kernel.org. [2604:1380:4601:e00::3]) by mx.google.com with ESMTPS id a9-20020aa7d909000000b005600a85158fsi1955096edr.566.2024.02.11.11.04.59 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 11 Feb 2024 11:04:59 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-60920-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) client-ip=2604:1380:4601:e00::3; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=a4uoH19M; arc=pass (i=1 spf=pass spfdomain=gmail.com dkim=pass dkdomain=gmail.com dmarc=pass fromdomain=gmail.com); spf=pass (google.com: domain of linux-kernel+bounces-60920-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-60920-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id 435221F224EC for ; Sun, 11 Feb 2024 19:04:58 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 0997D5D75A; Sun, 11 Feb 2024 19:03:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="a4uoH19M" Received: from mail-ej1-f49.google.com (mail-ej1-f49.google.com [209.85.218.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B64805DF03; Sun, 11 Feb 2024 19:03:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707678227; cv=none; b=uaeDjw/fDpir6YpFbNXx+3BL5lJWCXDd2TmyEzeNz8qwICdpLIy4Sdp/TILbgq/mpBkc+Uyfkf0p9JeeR5JDN/c9Ey8XEW/Xa9dcFNuio6ZCL8AonAGI+1QeqwzVk4024P5cCkOWS1T2lEFtIQnNd8HPHePiXASR4+TSpQVhMPk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707678227; c=relaxed/simple; bh=i/qUiKzMZn/uyW3tJL8mqyWiDYrn3OvyPt+hcFmuS+o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YKCnwPifsjKOZqycg2cn24ErsETdjbO0wSXYrDzN/1xVh31rZrGEDU4NuPoXoIrM/TN323pNEAbAQX7JmXKC+8eEatMTPqXVVKBR51Mb7ai5l2YAkacciepj34BpVaZR6W4M7XQmmkwwg03MIm+bbCIVanxNOJQLVG7qthY4BZA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=a4uoH19M; arc=none smtp.client-ip=209.85.218.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ej1-f49.google.com with SMTP id a640c23a62f3a-a3c0d92ca8aso208543966b.3; Sun, 11 Feb 2024 11:03:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1707678222; x=1708283022; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=6UELQfcO6ackvRjvkMbp0zi8LAe3DQMmzMATvXyQ8MY=; b=a4uoH19MR5qlP6oJtEZ+/dLEFgwhLaGhP6j0bg5TLhL/3OYUSR7bgoZ23pYhokPV/4 /uU1u21jFip1UnL7ajHGlW5ShxIRf9i13HPwKU7fl3sh3PWgG+OrUnmXr8XI6lKJ26sG qjaz/QvWmL7wouO/wVFEEubamECW8xgAsjSDuB8GyuHUNZ7ZgwoLA4/F8TZKcd9mgb7f Z41XouJzju3akWa16xSH5iVmlbAMUkwT91KjCbSnbbXOol9iwYbHNQJhQN5m1AqdgXz4 1HVNk1B6AaL/fmL5L1ZXFEUEjE3OAOdDC6uZToNwx3Ld2ybAW+pmsLYIdt/fdsmHnMVk lpnQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1707678222; x=1708283022; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=6UELQfcO6ackvRjvkMbp0zi8LAe3DQMmzMATvXyQ8MY=; b=P4WdUP94IZRc/YVEpjhQE9Je4cXnJKJ/2WZowO+aHCJXiIQ382sLMp0KmBQu6zJarG p30HOAXiitqKP1MTxDAG2EOcIJZk+P2QoyKmk1sJWksmHKRO/6OdSbXzUJGLZrZ4EkuR 1anD1gPQLKSWwb4B7kDXC8gcsqhFkPTJJyvXT2JEPyBSX5D/nGl9FpcN2P1+5UB6XwdQ YabVspt5ytl/EZ/uxTqtpa++5bT2mtxwjNVRPZq454x8ycVwr1qCM9TzP4h+F8lYYMgV g7RfoZCRxEHuy7BycuOe5tjYJiCaOeSeDxpw4/jfB2BLMNqSQXkfkAjlH7eIA3cO4PXj Fbag== X-Forwarded-Encrypted: i=1; AJvYcCWDngV1eQCESgkGRg6xWlV8plSWkPdBjucWlAhPWYvFZBvDmPGyzNNQCAQruRQx/+dJHeV7LnEAxT5Zg5vFqj6eWkP6MHt8EI6lghQlRv3GHNshRCI+cLeoDuVL/qQe+lftsPVYegdrEQ== X-Gm-Message-State: AOJu0Yxdmgddyzx8SI+yKnw03HU3qtn6RcT6o3MVHTF2MoCeK92GK3ew HjyN5q8skI5OrOJnAKtfvdwOniiky9RgM3XAPYHsK8Hh1QVcsQ8o X-Received: by 2002:a17:906:7b87:b0:a38:a2f:c131 with SMTP id s7-20020a1709067b8700b00a380a2fc131mr3160106ejo.43.1707678221483; Sun, 11 Feb 2024 11:03:41 -0800 (PST) X-Forwarded-Encrypted: i=1; AJvYcCWGGAwoZiePeWauc0jYGqaPhtGN359ySozEX2HQaZ/h/KggDrgLkYwCkKlpdE/J3oYGw62w9WFaErW+aXoj3fdnxIGGqJrs1lP2FBEd9riDCL12kOPN8CkK4tpq/nUdvWJ+hDVK6M+6HJYT2yCrmC+c9K05bkyQ+sZt4j0sBly7eW2+425bFKOOGrE16x4yNFnW7eqDwxIpOByTRO8XzUaXnSUbpzbP76hU100GspfpWfwPCKPQA8+loCqNI9xfzNu3SBto/QmwCginZA9EKHmQXfjJpbNDuwcIX1CWcFfn9wTnYD9D5+DLfAZ3un8W4EabaY9nwrdYO8BM2fER7wCaWMrsS7n5l7giZPXBvZCaMM6uVUbX3MsbeEqtwwgsjo2nbkQBPQWT138IJKZRMmQ+9vy9GE2H/MJ/3kXJWIdAo3HPK1s2ef/P5lF3BPVosgTILCcl+x+p5k2aPrv9kyY26UnplAbaZIXO2IJBws2dgeURUfYw8sBA5+B3yRVil9nwTYK91LXsB29Q5NuSodsxfrbKrQ0PKTJR9wRezGInMSWbY0jCPNoXoAEDCiuyH6Vc6I2UQ3JvqDwlf/5t72QlF4gPeHhUxzTAn3+Hz9Y= Received: from localhost.localdomain ([2a02:8109:aa27:2d00::2d2b]) by smtp.gmail.com with ESMTPSA id ps7-20020a170906bf4700b00a3c5fa1052csm1207400ejb.138.2024.02.11.11.03.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 11 Feb 2024 11:03:40 -0800 (PST) From: Mehdi Djait To: mchehab@kernel.org, heiko@sntech.de, hverkuil-cisco@xs4all.nl, krzysztof.kozlowski+dt@linaro.org, robh+dt@kernel.org, conor+dt@kernel.org Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, alexandre.belloni@bootlin.com, maxime.chevallier@bootlin.com, paul.kocialkowski@bootlin.com, michael.riesch@wolfvision.net, laurent.pinchart@ideasonboard.com, Mehdi Djait , Mehdi Djait Subject: [RESEND Patch v13 2/3] media: rockchip: Add a driver for Rockchip's camera interface Date: Sun, 11 Feb 2024 20:03:31 +0100 Message-ID: <715d89214d1ed6a8bb16cbb6268718a737485560.1707677804.git.mehdi.djait.k@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1790630433668913369 X-GMAIL-MSGID: 1790630480415662157 From: Mehdi Djait This introduces a V4L2 driver for the Rockchip CIF video capture controller. This controller supports multiple parallel interfaces, but for now only the BT.656 interface could be tested, hence it's the only one that's supported in the first version of this driver. This controller can be found on RK3066, PX30, RK1808, RK3128 and RK3288, but for now it's only been tested on the PX30. CIF is implemented as a video node-centric driver. Most of this driver was written following the BSP driver from Rockchip, removing the parts that either didn't fit correctly the guidelines, or that couldn't be tested. This basic version doesn't support cropping nor scaling and is only designed with one SDTV video decoder being attached to it at any time. This version uses the "pingpong" mode of the controller, which is a double-buffering mechanism. Reviewed-by: Michael Riesch Signed-off-by: Mehdi Djait Signed-off-by: Mehdi Djait --- MAINTAINERS | 7 + drivers/media/platform/rockchip/Kconfig | 1 + drivers/media/platform/rockchip/Makefile | 1 + drivers/media/platform/rockchip/cif/Kconfig | 14 + drivers/media/platform/rockchip/cif/Makefile | 3 + .../media/platform/rockchip/cif/cif-capture.c | 1111 +++++++++++++++++ .../media/platform/rockchip/cif/cif-capture.h | 20 + .../media/platform/rockchip/cif/cif-common.h | 128 ++ drivers/media/platform/rockchip/cif/cif-dev.c | 308 +++++ .../media/platform/rockchip/cif/cif-regs.h | 127 ++ 10 files changed, 1720 insertions(+) create mode 100644 drivers/media/platform/rockchip/cif/Kconfig create mode 100644 drivers/media/platform/rockchip/cif/Makefile create mode 100644 drivers/media/platform/rockchip/cif/cif-capture.c create mode 100644 drivers/media/platform/rockchip/cif/cif-capture.h create mode 100644 drivers/media/platform/rockchip/cif/cif-common.h create mode 100644 drivers/media/platform/rockchip/cif/cif-dev.c create mode 100644 drivers/media/platform/rockchip/cif/cif-regs.h diff --git a/MAINTAINERS b/MAINTAINERS index 1a89e0d2ac61..989a39c94eac 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18882,6 +18882,13 @@ F: Documentation/ABI/*/sysfs-driver-hid-roccat* F: drivers/hid/hid-roccat* F: include/linux/hid-roccat* +ROCKCHIP CIF DRIVER +M: Mehdi Djait +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/media/rockchip,px30-vip.yaml +F: drivers/media/platform/rockchip/cif/ + ROCKCHIP CRYPTO DRIVERS M: Corentin Labbe L: linux-crypto@vger.kernel.org diff --git a/drivers/media/platform/rockchip/Kconfig b/drivers/media/platform/rockchip/Kconfig index b41d3960c1b4..f73d68d1d2b6 100644 --- a/drivers/media/platform/rockchip/Kconfig +++ b/drivers/media/platform/rockchip/Kconfig @@ -2,5 +2,6 @@ comment "Rockchip media platform drivers" +source "drivers/media/platform/rockchip/cif/Kconfig" source "drivers/media/platform/rockchip/rga/Kconfig" source "drivers/media/platform/rockchip/rkisp1/Kconfig" diff --git a/drivers/media/platform/rockchip/Makefile b/drivers/media/platform/rockchip/Makefile index 4f782b876ac9..1a7aa1f8e134 100644 --- a/drivers/media/platform/rockchip/Makefile +++ b/drivers/media/platform/rockchip/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only +obj-y += cif/ obj-y += rga/ obj-y += rkisp1/ diff --git a/drivers/media/platform/rockchip/cif/Kconfig b/drivers/media/platform/rockchip/cif/Kconfig new file mode 100644 index 000000000000..1dfe9a167341 --- /dev/null +++ b/drivers/media/platform/rockchip/cif/Kconfig @@ -0,0 +1,14 @@ +config VIDEO_ROCKCHIP_CIF + tristate "Rockchip CIF Video Camera Interface" + depends on VIDEO_DEV + depends on ARCH_ROCKCHIP || COMPILE_TEST + depends on V4L_PLATFORM_DRIVERS + depends on PM && COMMON_CLK + select MEDIA_CONTROLLER + select VIDEOBUF2_DMA_CONTIG + select V4L2_FWNODE + select VIDEO_V4L2_SUBDEV_API + help + This is a driver for Rockchip SoC Camera interface. It supports + parallel interfaces such as BT.656. This camera interface is both + called VIP and CIF. diff --git a/drivers/media/platform/rockchip/cif/Makefile b/drivers/media/platform/rockchip/cif/Makefile new file mode 100644 index 000000000000..02a88f17d153 --- /dev/null +++ b/drivers/media/platform/rockchip/cif/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_VIDEO_ROCKCHIP_CIF) += rockchip-cif.o +rockchip-cif-objs += cif-dev.o cif-capture.o diff --git a/drivers/media/platform/rockchip/cif/cif-capture.c b/drivers/media/platform/rockchip/cif/cif-capture.c new file mode 100644 index 000000000000..2c7716684de0 --- /dev/null +++ b/drivers/media/platform/rockchip/cif/cif-capture.c @@ -0,0 +1,1111 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip CIF Camera Interface Driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Copyright (C) 2020 Maxime Chevallier + * Copyright (C) 2023 Mehdi Djait + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cif-capture.h" +#include "cif-common.h" +#include "cif-regs.h" + +#define CIF_REQ_BUFS_MIN 2 +#define CIF_MIN_WIDTH 64 +#define CIF_MIN_HEIGHT 64 +#define CIF_MAX_WIDTH 8192 +#define CIF_MAX_HEIGHT 8192 + +#define CIF_PLANE_Y 0 +#define CIF_PLANE_UV 1 + +static struct cif_output_fmt out_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_NV16, + .fmt_val = CIF_FORMAT_YUV_OUTPUT_422 | + CIF_FORMAT_UV_STORAGE_ORDER_UVUV, + .cplanes = 2, + }, { + .fourcc = V4L2_PIX_FMT_NV61, + .fmt_val = CIF_FORMAT_YUV_OUTPUT_422 | + CIF_FORMAT_UV_STORAGE_ORDER_VUVU, + .cplanes = 2, + }, + { + .fourcc = V4L2_PIX_FMT_NV12, + .fmt_val = CIF_FORMAT_YUV_OUTPUT_420 | + CIF_FORMAT_UV_STORAGE_ORDER_UVUV, + .cplanes = 2, + }, + { + .fourcc = V4L2_PIX_FMT_NV21, + .fmt_val = CIF_FORMAT_YUV_OUTPUT_420 | + CIF_FORMAT_UV_STORAGE_ORDER_VUVU, + .cplanes = 2, + }, { + .fourcc = V4L2_PIX_FMT_RGB24, + .cplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_RGB565, + .cplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_BGR666, + .cplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .cplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .cplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .cplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .cplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .cplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .cplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .cplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .cplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB12, + .cplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG12, + .cplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG12, + .cplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR12, + .cplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR16, + .cplanes = 1, + }, { + .fourcc = V4L2_PIX_FMT_Y16, + .cplanes = 1, + } +}; + +static const struct cif_input_fmt in_fmts[] = { + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + .dvp_fmt_val = CIF_FORMAT_YUV_INPUT_422 | + CIF_FORMAT_YUV_INPUT_ORDER_YUYV, + .fmt_type = CIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + .dvp_fmt_val = CIF_FORMAT_YUV_INPUT_422 | + CIF_FORMAT_YUV_INPUT_ORDER_YUYV, + .fmt_type = CIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_INTERLACED, + }, { + .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, + .dvp_fmt_val = CIF_FORMAT_YUV_INPUT_422 | + CIF_FORMAT_YUV_INPUT_ORDER_YVYU, + .fmt_type = CIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, + .dvp_fmt_val = CIF_FORMAT_YUV_INPUT_422 | + CIF_FORMAT_YUV_INPUT_ORDER_YVYU, + .fmt_type = CIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_INTERLACED, + }, { + .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, + .dvp_fmt_val = CIF_FORMAT_YUV_INPUT_422 | + CIF_FORMAT_YUV_INPUT_ORDER_UYVY, + .fmt_type = CIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, + .dvp_fmt_val = CIF_FORMAT_YUV_INPUT_422 | + CIF_FORMAT_YUV_INPUT_ORDER_UYVY, + .fmt_type = CIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_INTERLACED, + }, { + .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, + .dvp_fmt_val = CIF_FORMAT_YUV_INPUT_422 | + CIF_FORMAT_YUV_INPUT_ORDER_VYUY, + .fmt_type = CIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, + .dvp_fmt_val = CIF_FORMAT_YUV_INPUT_422 | + CIF_FORMAT_YUV_INPUT_ORDER_VYUY, + .fmt_type = CIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_INTERLACED, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .dvp_fmt_val = CIF_FORMAT_INPUT_MODE_RAW | + CIF_FORMAT_RAW_DATA_WIDTH_8, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .dvp_fmt_val = CIF_FORMAT_INPUT_MODE_RAW | + CIF_FORMAT_RAW_DATA_WIDTH_8, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .dvp_fmt_val = CIF_FORMAT_INPUT_MODE_RAW | + CIF_FORMAT_RAW_DATA_WIDTH_8, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .dvp_fmt_val = CIF_FORMAT_INPUT_MODE_RAW | + CIF_FORMAT_RAW_DATA_WIDTH_8, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .dvp_fmt_val = CIF_FORMAT_INPUT_MODE_RAW | + CIF_FORMAT_RAW_DATA_WIDTH_10, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .dvp_fmt_val = CIF_FORMAT_INPUT_MODE_RAW | + CIF_FORMAT_RAW_DATA_WIDTH_10, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .dvp_fmt_val = CIF_FORMAT_INPUT_MODE_RAW | + CIF_FORMAT_RAW_DATA_WIDTH_10, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .dvp_fmt_val = CIF_FORMAT_INPUT_MODE_RAW | + CIF_FORMAT_RAW_DATA_WIDTH_10, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + .dvp_fmt_val = CIF_FORMAT_INPUT_MODE_RAW | + CIF_FORMAT_RAW_DATA_WIDTH_12, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + .dvp_fmt_val = CIF_FORMAT_INPUT_MODE_RAW | + CIF_FORMAT_RAW_DATA_WIDTH_12, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + .dvp_fmt_val = CIF_FORMAT_INPUT_MODE_RAW | + CIF_FORMAT_RAW_DATA_WIDTH_12, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + .dvp_fmt_val = CIF_FORMAT_INPUT_MODE_RAW | + CIF_FORMAT_RAW_DATA_WIDTH_12, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_Y8_1X8, + .dvp_fmt_val = CIF_FORMAT_INPUT_MODE_RAW | + CIF_FORMAT_RAW_DATA_WIDTH_8, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_Y10_1X10, + .dvp_fmt_val = CIF_FORMAT_INPUT_MODE_RAW | + CIF_FORMAT_RAW_DATA_WIDTH_10, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, { + .mbus_code = MEDIA_BUS_FMT_Y12_1X12, + .dvp_fmt_val = CIF_FORMAT_INPUT_MODE_RAW | + CIF_FORMAT_RAW_DATA_WIDTH_12, + .fmt_type = CIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + } +}; + +static const struct +cif_input_fmt *get_input_fmt(struct v4l2_subdev *sd) +{ + struct v4l2_subdev_format fmt; + u32 i; + + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + fmt.pad = 0; + v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); + + for (i = 0; i < ARRAY_SIZE(in_fmts); i++) + if (fmt.format.code == in_fmts[i].mbus_code && + fmt.format.field == in_fmts[i].field) + return &in_fmts[i]; + + v4l2_err(sd->v4l2_dev, "remote's mbus code not supported\n"); + return NULL; +} + +static struct +cif_output_fmt *find_output_fmt(struct cif_stream *stream, u32 pixelfmt) +{ + struct cif_output_fmt *fmt; + u32 i; + + for (i = 0; i < ARRAY_SIZE(out_fmts); i++) { + fmt = &out_fmts[i]; + if (fmt->fourcc == pixelfmt) + return fmt; + } + + return NULL; +} + +static struct cif_buffer *cif_get_buffer(struct cif_stream *stream) +{ + struct cif_buffer *buff; + + lockdep_assert_held(&stream->vbq_lock); + + if (list_empty(&stream->buf_head)) + return NULL; + + buff = list_first_entry(&stream->buf_head, struct cif_buffer, queue); + list_del(&buff->queue); + + return buff; +} + +static int cif_init_buffers(struct cif_stream *stream) +{ + struct cif_device *cif_dev = stream->cifdev; + unsigned long lock_flags; + + spin_lock_irqsave(&stream->vbq_lock, lock_flags); + + stream->buffs[0] = cif_get_buffer(stream); + stream->buffs[1] = cif_get_buffer(stream); + + if (!(stream->buffs[0]) || !(stream->buffs[1])) { + spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); + return -EINVAL; + } + + stream->drop_frame = false; + + cif_write(cif_dev, CIF_FRM0_ADDR_Y, + stream->buffs[0]->buff_addr[CIF_PLANE_Y]); + cif_write(cif_dev, CIF_FRM0_ADDR_UV, + stream->buffs[0]->buff_addr[CIF_PLANE_UV]); + + cif_write(cif_dev, CIF_FRM1_ADDR_Y, + stream->buffs[1]->buff_addr[CIF_PLANE_Y]); + cif_write(cif_dev, CIF_FRM1_ADDR_UV, + stream->buffs[1]->buff_addr[CIF_PLANE_UV]); + + spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); + + return 0; +} + +static void cif_assign_new_buffer_pingpong(struct cif_stream *stream) +{ + struct cif_device *cif_dev = stream->cifdev; + struct cif_buffer *buffer = NULL; + u32 frm_addr_y, frm_addr_uv; + unsigned long lock_flags; + + spin_lock_irqsave(&stream->vbq_lock, lock_flags); + + buffer = cif_get_buffer(stream); + + /* + * In Pingpong mode: + * After one frame0 captured, CIF will start to capture the next frame1 + * automatically. + * + * If there is no buffer: + * 1. Make the next frame0 write to the buffer of frame1. + * + * 2. Drop the frame1: Don't return it to user-space, as it will be + * overwritten by the next frame0. + */ + if (!buffer) { + stream->drop_frame = true; + buffer = stream->buffs[1 - stream->frame_phase]; + } else { + stream->drop_frame = false; + } + + stream->buffs[stream->frame_phase] = buffer; + spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); + + frm_addr_y = stream->frame_phase ? CIF_FRM1_ADDR_Y : CIF_FRM0_ADDR_Y; + frm_addr_uv = stream->frame_phase ? CIF_FRM1_ADDR_UV : CIF_FRM0_ADDR_UV; + + cif_write(cif_dev, frm_addr_y, buffer->buff_addr[CIF_PLANE_Y]); + cif_write(cif_dev, frm_addr_uv, buffer->buff_addr[CIF_PLANE_UV]); +} + +static void cif_stream_stop(struct cif_stream *stream) +{ + struct cif_device *cif_dev = stream->cifdev; + u32 val; + + val = cif_read(cif_dev, CIF_CTRL); + cif_write(cif_dev, CIF_CTRL, val & (~CIF_CTRL_ENABLE_CAPTURE)); + cif_write(cif_dev, CIF_INTEN, 0x0); + cif_write(cif_dev, CIF_INTSTAT, 0x3ff); + cif_write(cif_dev, CIF_FRAME_STATUS, 0x0); + + stream->stopping = false; +} + +static int cif_queue_setup(struct vb2_queue *queue, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct cif_stream *stream = queue->drv_priv; + + if (*num_planes) + return sizes[0] < stream->pix.sizeimage ? -EINVAL : 0; + + *num_planes = 1; + sizes[0] = stream->pix.sizeimage; + + return 0; +} + +static void cif_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct cif_buffer *cifbuf = to_cif_buffer(vbuf); + struct vb2_queue *queue = vb->vb2_queue; + struct cif_stream *stream = queue->drv_priv; + struct v4l2_pix_format *pix = &stream->pix; + unsigned long lock_flags; + int i; + + struct cif_output_fmt *fmt = stream->cif_fmt_out; + + memset(cifbuf->buff_addr, 0, sizeof(cifbuf->buff_addr)); + + cifbuf->buff_addr[0] = vb2_dma_contig_plane_dma_addr(vb, 0); + + for (i = 0; i < fmt->cplanes - 1; i++) + cifbuf->buff_addr[i + 1] = cifbuf->buff_addr[i] + + pix->bytesperline * pix->height; + + spin_lock_irqsave(&stream->vbq_lock, lock_flags); + list_add_tail(&cifbuf->queue, &stream->buf_head); + spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); +} + +static void cif_return_all_buffers(struct cif_stream *stream, + enum vb2_buffer_state state) +{ + struct cif_buffer *buf; + unsigned long lock_flags; + + spin_lock_irqsave(&stream->vbq_lock, lock_flags); + + if (stream->buffs[0]) { + vb2_buffer_done(&stream->buffs[0]->vb.vb2_buf, state); + stream->buffs[0] = NULL; + } + + if (stream->buffs[1]) { + if (!stream->drop_frame) + vb2_buffer_done(&stream->buffs[1]->vb.vb2_buf, state); + + stream->buffs[1] = NULL; + } + + while (!list_empty(&stream->buf_head)) { + buf = cif_get_buffer(stream); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } + + spin_unlock_irqrestore(&stream->vbq_lock, lock_flags); +} + +static void cif_stop_streaming(struct vb2_queue *queue) +{ + struct cif_stream *stream = queue->drv_priv; + struct cif_device *cif_dev = stream->cifdev; + struct v4l2_subdev *sd = cif_dev->remote.sd; + int ret; + + v4l2_subdev_call(sd, video, s_stream, 0); + + stream->stopping = true; + ret = wait_event_timeout(stream->wq_stopped, + !stream->stopping, + msecs_to_jiffies(1000)); + if (!ret) + cif_stream_stop(stream); + + pm_runtime_put(cif_dev->dev); + + cif_return_all_buffers(stream, VB2_BUF_STATE_ERROR); +} + +static int cif_stream_start(struct cif_stream *stream) +{ + u32 val, fmt_type, xfer_mode = 0; + struct cif_device *cif_dev = stream->cifdev; + struct cif_remote *remote_info = &cif_dev->remote; + int ret; + u32 input_mode; + + stream->frame_idx = 0; + stream->frame_phase = 0; + + fmt_type = stream->cif_fmt_in->fmt_type; + input_mode = (remote_info->std == V4L2_STD_NTSC) ? + CIF_FORMAT_INPUT_MODE_NTSC : + CIF_FORMAT_INPUT_MODE_PAL; + + val = input_mode | stream->cif_fmt_out->fmt_val | + stream->cif_fmt_in->dvp_fmt_val | xfer_mode; + cif_write(cif_dev, CIF_FOR, val); + + val = stream->pix.width; + if (stream->cif_fmt_in->fmt_type == CIF_FMT_TYPE_RAW) + val = stream->pix.width * 2; + + cif_write(cif_dev, CIF_VIR_LINE_WIDTH, val); + cif_write(cif_dev, CIF_SET_SIZE, + stream->pix.width | (stream->pix.height << 16)); + + cif_write(cif_dev, CIF_FRAME_STATUS, CIF_FRAME_STAT_CLS); + cif_write(cif_dev, CIF_INTSTAT, CIF_INTSTAT_CLS); + cif_write(cif_dev, CIF_SCL_CTRL, (fmt_type == CIF_FMT_TYPE_YUV) ? + CIF_SCL_CTRL_ENABLE_YUV_16BIT_BYPASS : + CIF_SCL_CTRL_ENABLE_RAW_16BIT_BYPASS); + + ret = cif_init_buffers(stream); + if (ret) + return ret; + + cif_write(cif_dev, CIF_INTEN, CIF_INTEN_FRAME_END_EN | + CIF_INTEN_LINE_ERR_EN | + CIF_INTEN_PST_INF_FRAME_END_EN); + + cif_write(cif_dev, CIF_CTRL, CIF_CTRL_AXI_BURST_16 | + CIF_CTRL_MODE_PINGPONG | + CIF_CTRL_ENABLE_CAPTURE); + + return 0; +} + +static int cif_start_streaming(struct vb2_queue *queue, unsigned int count) +{ + struct cif_stream *stream = queue->drv_priv; + struct cif_device *cif_dev = stream->cifdev; + struct v4l2_device *v4l2_dev = &cif_dev->v4l2_dev; + struct v4l2_subdev *sd; + int ret; + + if (!cif_dev->remote.sd) { + ret = -ENODEV; + v4l2_err(v4l2_dev, "No remote subdev detected\n"); + goto destroy_buf; + } + + ret = pm_runtime_resume_and_get(cif_dev->dev); + if (ret < 0) { + v4l2_err(v4l2_dev, "Failed to get runtime pm, %d\n", ret); + goto destroy_buf; + } + + sd = cif_dev->remote.sd; + + stream->cif_fmt_in = get_input_fmt(cif_dev->remote.sd); + if (!stream->cif_fmt_in) + goto runtime_put; + + ret = cif_stream_start(stream); + if (ret < 0) + goto stop_stream; + + ret = v4l2_subdev_call(sd, video, s_stream, 1); + if (ret < 0) + goto stop_stream; + + return 0; + +stop_stream: + cif_stream_stop(stream); +runtime_put: + pm_runtime_put(cif_dev->dev); +destroy_buf: + cif_return_all_buffers(stream, VB2_BUF_STATE_QUEUED); + + return ret; +} + +static const struct vb2_ops cif_vb2_ops = { + .queue_setup = cif_queue_setup, + .buf_queue = cif_buf_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .stop_streaming = cif_stop_streaming, + .start_streaming = cif_start_streaming, +}; + +static int cif_init_vb2_queue(struct vb2_queue *q, + struct cif_stream *stream) +{ + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->drv_priv = stream; + q->ops = &cif_vb2_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct cif_buffer); + q->min_queued_buffers = CIF_REQ_BUFS_MIN; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &stream->vlock; + q->dev = stream->cifdev->dev; + + return vb2_queue_init(q); +} + +static void cif_update_pix(struct cif_stream *stream, + struct cif_output_fmt *fmt, + struct v4l2_pix_format *pix) +{ + struct cif_remote *remote_info = &stream->cifdev->remote; + struct v4l2_subdev_format sd_fmt; + u32 width, height; + + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_fmt.pad = 0; + v4l2_subdev_call(remote_info->sd, pad, get_fmt, NULL, &sd_fmt); + + width = clamp_t(u32, sd_fmt.format.width, + CIF_MIN_WIDTH, CIF_MAX_WIDTH); + height = clamp_t(u32, sd_fmt.format.height, + CIF_MIN_HEIGHT, CIF_MAX_HEIGHT); + + pix->width = width; + pix->height = height; + pix->field = sd_fmt.format.field; + pix->colorspace = sd_fmt.format.colorspace; + pix->ycbcr_enc = sd_fmt.format.ycbcr_enc; + pix->quantization = sd_fmt.format.quantization; + pix->xfer_func = sd_fmt.format.xfer_func; + + v4l2_fill_pixfmt(pix, fmt->fourcc, pix->width, pix->height); +} + +static int cif_set_fmt(struct cif_stream *stream, + struct v4l2_pix_format *pix) +{ + struct cif_device *cif_dev = stream->cifdev; + struct v4l2_subdev_format sd_fmt; + struct cif_output_fmt *fmt; + int ret; + + if (vb2_is_streaming(&stream->buf_queue)) + return -EBUSY; + + fmt = find_output_fmt(stream, pix->pixelformat); + if (!fmt) + fmt = &out_fmts[0]; + + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_fmt.pad = 0; + sd_fmt.format.width = pix->width; + sd_fmt.format.height = pix->height; + + ret = v4l2_subdev_call(cif_dev->remote.sd, pad, set_fmt, NULL, &sd_fmt); + if (ret) + return ret; + + cif_update_pix(stream, fmt, pix); + stream->pix = *pix; + stream->cif_fmt_out = fmt; + + return 0; +} + +void cif_set_default_format(struct cif_device *cif_dev) +{ + struct cif_stream *stream = &cif_dev->stream; + struct v4l2_pix_format pix; + + cif_dev->remote.std = V4L2_STD_NTSC; + + pix.pixelformat = V4L2_PIX_FMT_NV12; + pix.width = CIF_DEFAULT_WIDTH; + pix.height = CIF_DEFAULT_HEIGHT; + + cif_set_fmt(stream, &pix); +} + +void cif_stream_init(struct cif_device *cif_dev) +{ + struct cif_stream *stream = &cif_dev->stream; + struct v4l2_pix_format pix; + + memset(stream, 0, sizeof(*stream)); + memset(&pix, 0, sizeof(pix)); + stream->cifdev = cif_dev; + + INIT_LIST_HEAD(&stream->buf_head); + spin_lock_init(&stream->vbq_lock); + init_waitqueue_head(&stream->wq_stopped); +} + +static const struct v4l2_file_operations cif_fops = { + .open = v4l2_fh_open, + .release = vb2_fop_release, + .unlocked_ioctl = video_ioctl2, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, +}; + +static int cif_enum_input(struct file *file, void *priv, + struct v4l2_input *input) +{ + struct cif_stream *stream = video_drvdata(file); + struct v4l2_subdev *sd = stream->cifdev->remote.sd; + int ret; + + if (input->index > 0) + return -EINVAL; + + ret = v4l2_subdev_call(sd, video, g_input_status, &input->status); + if (ret && ret != -EOPNOTSUPP) + return ret; + + strscpy(input->name, "Camera", sizeof(input->name)); + input->type = V4L2_INPUT_TYPE_CAMERA; + input->std = stream->vdev.tvnorms; + input->capabilities = V4L2_IN_CAP_STD; + + return 0; +} + +static int cif_g_std(struct file *file, void *fh, v4l2_std_id *norm) +{ + struct cif_stream *stream = video_drvdata(file); + struct cif_remote *remote_info = &stream->cifdev->remote; + + *norm = remote_info->std; + + return 0; +} + +static int cif_s_std(struct file *file, void *fh, v4l2_std_id norm) +{ + struct cif_stream *stream = video_drvdata(file); + struct cif_remote *remote_info = &stream->cifdev->remote; + int ret; + + if (norm == remote_info->std) + return 0; + + if (vb2_is_busy(&stream->buf_queue)) + return -EBUSY; + + ret = v4l2_subdev_call(remote_info->sd, video, s_std, norm); + if (ret) + return ret; + + remote_info->std = norm; + + /* S_STD will update the format since that depends on the standard. */ + cif_update_pix(stream, stream->cif_fmt_out, &stream->pix); + + return 0; +} + +static int cif_querystd(struct file *file, void *fh, v4l2_std_id *a) +{ + struct cif_stream *stream = video_drvdata(file); + struct cif_remote *remote_info = &stream->cifdev->remote; + + *a = V4L2_STD_UNKNOWN; + + return v4l2_subdev_call(remote_info->sd, video, querystd, a); +} + +static int cif_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct cif_output_fmt *fmt = NULL; + + if (f->index >= ARRAY_SIZE(out_fmts)) + return -EINVAL; + + fmt = &out_fmts[f->index]; + f->pixelformat = fmt->fourcc; + + return 0; +} + +static int cif_try_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct cif_stream *stream = video_drvdata(file); + struct cif_output_fmt *fmt; + + fmt = find_output_fmt(stream, f->fmt.pix.pixelformat); + if (!fmt) + fmt = &out_fmts[0]; + + cif_update_pix(stream, fmt, &f->fmt.pix); + + return 0; +} + +static int cif_s_fmt_vid_cap(struct file *file, + void *priv, struct v4l2_format *f) +{ + struct cif_stream *stream = video_drvdata(file); + int ret; + + if (vb2_is_busy(&stream->buf_queue)) + return -EBUSY; + + ret = cif_set_fmt(stream, &f->fmt.pix); + + return ret; +} + +static int cif_g_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct cif_stream *stream = video_drvdata(file); + + f->fmt.pix = stream->pix; + + return 0; +} + +static int cif_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct cif_stream *stream = video_drvdata(file); + struct device *dev = stream->cifdev->dev; + + strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); + strscpy(cap->card, dev->driver->name, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", dev_name(dev)); + + return 0; +} + +static int cif_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct cif_stream *stream = video_drvdata(file); + struct cif_device *cif_dev = stream->cifdev; + struct v4l2_subdev_frame_size_enum fse = { + .index = fsize->index, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct cif_output_fmt *fmt; + int ret; + + if (!cif_dev->remote.sd) + return -ENODEV; + + fmt = find_output_fmt(stream, fsize->pixel_format); + if (!fmt) + return -EINVAL; + + fse.code = fmt->mbus; + + ret = v4l2_subdev_call(cif_dev->remote.sd, pad, enum_frame_size, + NULL, &fse); + if (ret) + return ret; + + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = fse.max_width; + fsize->discrete.height = fse.max_height; + + return 0; +} + +static int cif_enum_frameintervals(struct file *file, void *fh, + struct v4l2_frmivalenum *fival) +{ + struct cif_stream *stream = video_drvdata(file); + struct cif_device *cif_dev = stream->cifdev; + struct v4l2_subdev_frame_interval_enum fie = { + .index = fival->index, + .width = fival->width, + .height = fival->height, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct cif_output_fmt *fmt; + int ret; + + if (!cif_dev->remote.sd) + return -ENODEV; + + fmt = find_output_fmt(stream, fival->pixel_format); + if (!fmt) + return -EINVAL; + + fie.code = fmt->mbus; + + ret = v4l2_subdev_call(cif_dev->remote.sd, pad, enum_frame_interval, + NULL, &fie); + if (ret) + return ret; + + fival->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fival->discrete = fie.interval; + + return 0; +} + +static int cif_g_input(struct file *file, void *fh, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int cif_s_input(struct file *file, void *fh, unsigned int i) +{ + if (i) + return -EINVAL; + + return 0; +} + +static int cif_g_parm(struct file *file, void *priv, struct v4l2_streamparm *p) +{ + struct cif_stream *stream = video_drvdata(file); + struct cif_device *cif_dev = stream->cifdev; + + if (!cif_dev->remote.sd) + return -ENODEV; + + return v4l2_g_parm_cap(video_devdata(file), cif_dev->remote.sd, p); +} + +static int cif_s_parm(struct file *file, void *priv, struct v4l2_streamparm *p) +{ + struct cif_stream *stream = video_drvdata(file); + struct cif_device *cif_dev = stream->cifdev; + + if (!cif_dev->remote.sd) + return -ENODEV; + + return v4l2_s_parm_cap(video_devdata(file), cif_dev->remote.sd, p); +} + +static const struct v4l2_ioctl_ops cif_v4l2_ioctl_ops = { + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_g_std = cif_g_std, + .vidioc_s_std = cif_s_std, + .vidioc_querystd = cif_querystd, + + .vidioc_enum_fmt_vid_cap = cif_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = cif_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = cif_s_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = cif_g_fmt_vid_cap, + .vidioc_querycap = cif_querycap, + .vidioc_enum_framesizes = cif_enum_framesizes, + .vidioc_enum_frameintervals = cif_enum_frameintervals, + + .vidioc_enum_input = cif_enum_input, + .vidioc_g_input = cif_g_input, + .vidioc_s_input = cif_s_input, + + .vidioc_g_parm = cif_g_parm, + .vidioc_s_parm = cif_s_parm, +}; + +void cif_unregister_stream_vdev(struct cif_device *cif_dev) +{ + struct cif_stream *stream = &cif_dev->stream; + + media_entity_cleanup(&stream->vdev.entity); + video_unregister_device(&stream->vdev); +} + +int cif_register_stream_vdev(struct cif_device *cif_dev) +{ + struct cif_stream *stream = &cif_dev->stream; + struct v4l2_device *v4l2_dev = &cif_dev->v4l2_dev; + struct video_device *vdev = &stream->vdev; + int ret; + + strscpy(vdev->name, CIF_DRIVER_NAME, sizeof(vdev->name)); + mutex_init(&stream->vlock); + + vdev->ioctl_ops = &cif_v4l2_ioctl_ops; + vdev->release = video_device_release_empty; + vdev->fops = &cif_fops; + vdev->minor = -1; + vdev->v4l2_dev = v4l2_dev; + vdev->lock = &stream->vlock; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING; + vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL; + video_set_drvdata(vdev, stream); + vdev->vfl_dir = VFL_DIR_RX; + stream->pad.flags = MEDIA_PAD_FL_SINK; + + cif_init_vb2_queue(&stream->buf_queue, stream); + + vdev->queue = &stream->buf_queue; + strscpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name)); + + ret = media_entity_pads_init(&vdev->entity, 1, &stream->pad); + if (ret < 0) + return ret; + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret < 0) + v4l2_err(v4l2_dev, + "video_register_device failed with error %d\n", ret); + + return ret; +} + +static void cif_vb_done(struct cif_stream *stream, + struct vb2_v4l2_buffer *vb_done) +{ + vb2_set_plane_payload(&vb_done->vb2_buf, 0, + stream->pix.sizeimage); + vb_done->vb2_buf.timestamp = ktime_get_ns(); + vb_done->sequence = stream->frame_idx; + vb2_buffer_done(&vb_done->vb2_buf, VB2_BUF_STATE_DONE); +} + +static void cif_reset_stream(struct cif_device *cif_dev) +{ + u32 ctl = cif_read(cif_dev, CIF_CTRL); + + cif_write(cif_dev, CIF_CTRL, ctl & (~CIF_CTRL_ENABLE_CAPTURE)); + cif_write(cif_dev, CIF_CTRL, ctl | CIF_CTRL_ENABLE_CAPTURE); +} + +irqreturn_t cif_irq_pingpong(int irq, void *ctx) +{ + struct device *dev = ctx; + struct cif_device *cif_dev = dev_get_drvdata(dev); + struct cif_stream *stream = &cif_dev->stream; + unsigned int intstat; + u32 lastline, lastpix, ctl, cif_frmst; + + intstat = cif_read(cif_dev, CIF_INTSTAT); + cif_frmst = cif_read(cif_dev, CIF_FRAME_STATUS); + lastline = CIF_FETCH_Y_LAST_LINE(cif_read(cif_dev, CIF_LAST_LINE)); + lastpix = CIF_FETCH_Y_LAST_LINE(cif_read(cif_dev, CIF_LAST_PIX)); + ctl = cif_read(cif_dev, CIF_CTRL); + + /* + * There are two irqs enabled: + * - PST_INF_FRAME_END: cif FIFO is ready, + * this is prior to FRAME_END + * - FRAME_END: cif has saved frame to memory, + * a frame ready + */ + + if (intstat & CIF_INTSTAT_PST_INF_FRAME_END) { + cif_write(cif_dev, CIF_INTSTAT, + CIF_INTSTAT_PST_INF_FRAME_END_CLR); + + if (stream->stopping) + /* To stop CIF ASAP, before FRAME_END irq. */ + cif_write(cif_dev, CIF_CTRL, + ctl & (~CIF_CTRL_ENABLE_CAPTURE)); + } + + if (intstat & CIF_INTSTAT_PRE_INF_FRAME_END) + cif_write(cif_dev, CIF_INTSTAT, CIF_INTSTAT_PRE_INF_FRAME_END); + + if (intstat & (CIF_INTSTAT_LINE_ERR | CIF_INTSTAT_PIX_ERR)) { + v4l2_err(&cif_dev->v4l2_dev, + "LINE_ERR OR PIX_ERR detected, stream will be reset"); + cif_write(cif_dev, CIF_INTSTAT, CIF_INTSTAT_LINE_ERR | + CIF_INTSTAT_PIX_ERR); + cif_reset_stream(cif_dev); + } + + if (intstat & CIF_INTSTAT_FRAME_END) { + struct vb2_v4l2_buffer *vb_done = NULL; + + cif_write(cif_dev, CIF_INTSTAT, CIF_INTSTAT_FRAME_END_CLR | + CIF_INTSTAT_LINE_END_CLR); + + if (stream->stopping) { + cif_stream_stop(stream); + wake_up(&stream->wq_stopped); + return IRQ_HANDLED; + } + + if (lastline != stream->pix.height) { + v4l2_err(&cif_dev->v4l2_dev, + "Bad frame, irq:%#x frmst:%#x size:%dx%d\n", + intstat, cif_frmst, lastpix, lastline); + + cif_reset_stream(cif_dev); + } + + if (cif_frmst & CIF_INTSTAT_F0_READY) + stream->frame_phase = 0; + else if (cif_frmst & CIF_INTSTAT_F1_READY) + stream->frame_phase = 1; + else + return IRQ_HANDLED; + + vb_done = &stream->buffs[stream->frame_phase]->vb; + if (!stream->drop_frame) { + cif_vb_done(stream, vb_done); + stream->frame_idx++; + } + + cif_assign_new_buffer_pingpong(stream); + } + + return IRQ_HANDLED; +} diff --git a/drivers/media/platform/rockchip/cif/cif-capture.h b/drivers/media/platform/rockchip/cif/cif-capture.h new file mode 100644 index 000000000000..0f457693a7a5 --- /dev/null +++ b/drivers/media/platform/rockchip/cif/cif-capture.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Rockchip CIF Driver + * + * Copyright (C) 2023 Mehdi Djait + */ + +#ifndef _CIF_CAPTURE_H +#define _CIF_CAPTURE_H + +struct cif_device; + +void cif_unregister_stream_vdev(struct cif_device *dev); +int cif_register_stream_vdev(struct cif_device *dev); +void cif_stream_init(struct cif_device *dev); +void cif_set_default_format(struct cif_device *dev); + +irqreturn_t cif_irq_pingpong(int irq, void *ctx); + +#endif diff --git a/drivers/media/platform/rockchip/cif/cif-common.h b/drivers/media/platform/rockchip/cif/cif-common.h new file mode 100644 index 000000000000..89ed9dd6f36d --- /dev/null +++ b/drivers/media/platform/rockchip/cif/cif-common.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Rockchip CIF Driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Copyright (C) 2023 Mehdi Djait + */ + +#ifndef _CIF_COMMON_H +#define _CIF_COMMON_H + +#include +#include + +#include +#include +#include +#include +#include + +#define CIF_DRIVER_NAME "rockchip-cif" + +#define CIF_MAX_BUS_CLK 8 +#define CIF_MAX_SENSOR 1 +#define CIF_MAX_RESET 5 + +#define CIF_DEFAULT_WIDTH 640 +#define CIF_DEFAULT_HEIGHT 480 + +struct cif_buffer { + struct vb2_v4l2_buffer vb; + struct list_head queue; + u32 buff_addr[VIDEO_MAX_PLANES]; +}; + +static inline struct cif_buffer *to_cif_buffer(struct vb2_v4l2_buffer *vb) +{ + return container_of(vb, struct cif_buffer, vb); +} + +struct cif_remote { + struct v4l2_subdev *sd; + int pad; + int lanes; + v4l2_std_id std; +}; + +struct cif_output_fmt { + u32 fourcc; + u32 mbus; + u32 fmt_val; + u8 cplanes; +}; + +enum cif_fmt_type { + CIF_FMT_TYPE_YUV = 0, + CIF_FMT_TYPE_RAW, +}; + +struct cif_input_fmt { + u32 mbus_code; + u32 dvp_fmt_val; + enum cif_fmt_type fmt_type; + enum v4l2_field field; +}; + +struct cif_stream { + struct cif_device *cifdev; + bool stopping; + wait_queue_head_t wq_stopped; + int frame_idx; + int frame_phase; + bool drop_frame; + + /* Lock between irq and buf_queue, buffs. */ + spinlock_t vbq_lock; + struct vb2_queue buf_queue; + struct list_head buf_head; + struct cif_buffer *buffs[2]; + + /* Lock used by the V4L core. */ + struct mutex vlock; + struct video_device vdev; + struct media_pad pad; + + struct cif_output_fmt *cif_fmt_out; + const struct cif_input_fmt *cif_fmt_in; + struct v4l2_pix_format pix; +}; + +static inline struct cif_stream *to_cif_stream(struct video_device *vdev) +{ + return container_of(vdev, struct cif_stream, vdev); +} + +struct cif_match_data { + struct clk_bulk_data *clks; + int clks_num; +}; + +struct cif_device { + struct device *dev; + int irq; + void __iomem *base_addr; + struct reset_control *cif_rst; + + struct v4l2_device v4l2_dev; + struct media_device media_dev; + struct v4l2_async_notifier notifier; + struct v4l2_async_connection asd; + struct cif_remote remote; + + struct cif_stream stream; + const struct cif_match_data *match_data; +}; + +static inline void cif_write(struct cif_device *cif_dev, unsigned int addr, + u32 val) +{ + writel(val, cif_dev->base_addr + addr); +} + +static inline u32 cif_read(struct cif_device *cif_dev, unsigned int addr) +{ + return readl(cif_dev->base_addr + addr); +} + +#endif diff --git a/drivers/media/platform/rockchip/cif/cif-dev.c b/drivers/media/platform/rockchip/cif/cif-dev.c new file mode 100644 index 000000000000..660e28397916 --- /dev/null +++ b/drivers/media/platform/rockchip/cif/cif-dev.c @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip CIF Camera Interface Driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Copyright (C) 2020 Maxime Chevallier + * Copyright (C) 2023 Mehdi Djait + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cif-capture.h" +#include "cif-common.h" +#include "cif-regs.h" + +static int subdev_notifier_complete(struct v4l2_async_notifier *notifier) +{ + struct cif_device *cif_dev; + struct v4l2_subdev *sd; + int ret; + + cif_dev = container_of(notifier, struct cif_device, notifier); + sd = cif_dev->remote.sd; + + mutex_lock(&cif_dev->media_dev.graph_mutex); + + ret = v4l2_device_register_subdev_nodes(&cif_dev->v4l2_dev); + if (ret < 0) + goto unlock; + + ret = media_create_pad_link(&sd->entity, 0, + &cif_dev->stream.vdev.entity, 0, + MEDIA_LNK_FL_ENABLED); + if (ret) + dev_err(cif_dev->dev, "failed to create link"); + +unlock: + mutex_unlock(&cif_dev->media_dev.graph_mutex); + return ret; +} + +static int subdev_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_connection *asd) +{ + struct cif_device *cif_dev = container_of(notifier, + struct cif_device, notifier); + int pad; + + cif_dev->remote.sd = subdev; + pad = media_entity_get_fwnode_pad(&subdev->entity, subdev->fwnode, + MEDIA_PAD_FL_SOURCE); + if (pad < 0) + return pad; + + cif_dev->remote.pad = pad; + + return 0; +} + +static const struct v4l2_async_notifier_operations subdev_notifier_ops = { + .bound = subdev_notifier_bound, + .complete = subdev_notifier_complete, +}; + +static int cif_subdev_notifier(struct cif_device *cif_dev) +{ + struct v4l2_async_notifier *ntf = &cif_dev->notifier; + struct device *dev = cif_dev->dev; + struct v4l2_async_connection *asd; + struct v4l2_fwnode_endpoint vep = { + .bus_type = V4L2_MBUS_UNKNOWN, + }; + struct fwnode_handle *ep; + int ret; + + v4l2_async_nf_init(ntf, &cif_dev->v4l2_dev); + + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + if (!ep) + return -ENODEV; + + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + if (ret) + goto complete; + + if (vep.bus_type != V4L2_MBUS_BT656 && + vep.bus_type != V4L2_MBUS_PARALLEL) { + v4l2_err(&cif_dev->v4l2_dev, "unsupported bus type\n"); + goto complete; + } + + asd = v4l2_async_nf_add_fwnode_remote(ntf, ep, + struct v4l2_async_connection); + if (IS_ERR(asd)) { + ret = PTR_ERR(asd); + goto complete; + } + + ntf->ops = &subdev_notifier_ops; + + ret = v4l2_async_nf_register(ntf); + if (ret) + v4l2_async_nf_cleanup(ntf); + +complete: + fwnode_handle_put(ep); + + return ret; +} + +static struct clk_bulk_data px30_cif_clks[] = { + { .id = "aclk", }, + { .id = "hclk", }, + { .id = "pclk", }, +}; + +static const struct cif_match_data px30_cif_match_data = { + .clks = px30_cif_clks, + .clks_num = ARRAY_SIZE(px30_cif_clks), +}; + +static const struct of_device_id cif_plat_of_match[] = { + { + .compatible = "rockchip,px30-vip", + .data = &px30_cif_match_data, + }, + {}, +}; + +static int cif_plat_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct v4l2_device *v4l2_dev; + struct cif_device *cif_dev; + struct resource *res; + int ret, irq; + + cif_dev = devm_kzalloc(dev, sizeof(*cif_dev), GFP_KERNEL); + if (!cif_dev) + return -ENOMEM; + + cif_dev->match_data = of_device_get_match_data(dev); + if (!cif_dev->match_data) + return -ENODEV; + + platform_set_drvdata(pdev, cif_dev); + cif_dev->dev = dev; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_irq(dev, irq, cif_irq_pingpong, IRQF_SHARED, + dev_driver_string(dev), dev); + if (ret) + return dev_err_probe(dev, ret, "request irq failed\n"); + + cif_dev->irq = irq; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, + "Unable to allocate resources for device\n"); + return -ENODEV; + } + + cif_dev->base_addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(cif_dev->base_addr)) + return PTR_ERR(cif_dev->base_addr); + + ret = devm_clk_bulk_get(dev, cif_dev->match_data->clks_num, + cif_dev->match_data->clks); + if (ret) + return ret; + + cif_dev->cif_rst = devm_reset_control_array_get(dev, false, false); + if (IS_ERR(cif_dev->cif_rst)) + return PTR_ERR(cif_dev->cif_rst); + + cif_stream_init(cif_dev); + strscpy(cif_dev->media_dev.model, "cif", + sizeof(cif_dev->media_dev.model)); + cif_dev->media_dev.dev = &pdev->dev; + v4l2_dev = &cif_dev->v4l2_dev; + v4l2_dev->mdev = &cif_dev->media_dev; + strscpy(v4l2_dev->name, "rockchip-cif", sizeof(v4l2_dev->name)); + + ret = v4l2_device_register(cif_dev->dev, &cif_dev->v4l2_dev); + if (ret < 0) + return ret; + + media_device_init(&cif_dev->media_dev); + + ret = media_device_register(&cif_dev->media_dev); + if (ret < 0) + goto err_unreg_v4l2_dev; + + /* Create & register platform subdev. */ + ret = cif_register_stream_vdev(cif_dev); + if (ret < 0) + goto err_unreg_media_dev; + + ret = cif_subdev_notifier(cif_dev); + if (ret < 0) { + v4l2_err(&cif_dev->v4l2_dev, + "Failed to register subdev notifier(%d)\n", ret); + goto err_unreg_stream_vdev; + } + + cif_set_default_format(cif_dev); + + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + return 0; + +err_unreg_stream_vdev: + cif_unregister_stream_vdev(cif_dev); +err_unreg_media_dev: + media_device_unregister(&cif_dev->media_dev); +err_unreg_v4l2_dev: + v4l2_device_unregister(&cif_dev->v4l2_dev); + return ret; +} + +static int cif_plat_remove(struct platform_device *pdev) +{ + struct cif_device *cif_dev = platform_get_drvdata(pdev); + + media_device_unregister(&cif_dev->media_dev); + v4l2_device_unregister(&cif_dev->v4l2_dev); + cif_unregister_stream_vdev(cif_dev); + + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static int cif_runtime_suspend(struct device *dev) +{ + struct cif_device *cif_dev = dev_get_drvdata(dev); + + clk_bulk_disable_unprepare(cif_dev->match_data->clks_num, + cif_dev->match_data->clks); + + reset_control_assert(cif_dev->cif_rst); + + return 0; +} + +static int cif_runtime_resume(struct device *dev) +{ + struct cif_device *cif_dev = dev_get_drvdata(dev); + int ret; + + ret = reset_control_deassert(cif_dev->cif_rst); + if (ret) { + dev_err(dev, "failed to deassert reset\n"); + return ret; + } + + ret = clk_bulk_prepare_enable(cif_dev->match_data->clks_num, + cif_dev->match_data->clks); + if (ret) { + dev_err(dev, "failed to enable module clock\n"); + goto err_reset; + } + + return 0; + +err_reset: + reset_control_assert(cif_dev->cif_rst); + + return ret; +} + +static const struct dev_pm_ops cif_plat_pm_ops = { + .runtime_suspend = cif_runtime_suspend, + .runtime_resume = cif_runtime_resume, +}; + +static struct platform_driver cif_plat_drv = { + .driver = { + .name = CIF_DRIVER_NAME, + .of_match_table = cif_plat_of_match, + .pm = &cif_plat_pm_ops, + }, + .probe = cif_plat_probe, + .remove = cif_plat_remove, +}; +module_platform_driver(cif_plat_drv); + +MODULE_AUTHOR("Rockchip Camera/ISP team"); +MODULE_DESCRIPTION("Rockchip CIF platform driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/rockchip/cif/cif-regs.h b/drivers/media/platform/rockchip/cif/cif-regs.h new file mode 100644 index 000000000000..b8500f0a9ac1 --- /dev/null +++ b/drivers/media/platform/rockchip/cif/cif-regs.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Rockchip CIF Driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Copyright (C) 2023 Mehdi Djait + */ + +#ifndef _CIF_REGS_H +#define _CIF_REGS_H + +#define CIF_CTRL 0x00 +#define CIF_INTEN 0x04 +#define CIF_INTSTAT 0x08 +#define CIF_FOR 0x0c +#define CIF_LINE_NUM_ADDR 0x10 +#define CIF_FRM0_ADDR_Y 0x14 +#define CIF_FRM0_ADDR_UV 0x18 +#define CIF_FRM1_ADDR_Y 0x1c +#define CIF_FRM1_ADDR_UV 0x20 +#define CIF_VIR_LINE_WIDTH 0x24 +#define CIF_SET_SIZE 0x28 +#define CIF_SCM_ADDR_Y 0x2c +#define CIF_SCM_ADDR_U 0x30 +#define CIF_SCM_ADDR_V 0x34 +#define CIF_WB_UP_FILTER 0x38 +#define CIF_WB_LOW_FILTER 0x3c +#define CIF_WBC_CNT 0x40 +#define CIF_CROP 0x44 +#define CIF_SCL_CTRL 0x48 +#define CIF_SCL_DST 0x4c +#define CIF_SCL_FCT 0x50 +#define CIF_SCL_VALID_NUM 0x54 +#define CIF_LINE_LOOP_CTR 0x58 +#define CIF_FRAME_STATUS 0x60 +#define CIF_CUR_DST 0x64 +#define CIF_LAST_LINE 0x68 +#define CIF_LAST_PIX 0x6c +#define CIF_FETCH_Y_LAST_LINE(VAL) ((VAL) & 0x1fff) + +#define CIF_CTRL_ENABLE_CAPTURE BIT(0) +#define CIF_CTRL_MODE_PINGPONG BIT(1) +#define CIF_CTRL_MODE_LINELOOP BIT(2) +#define CIF_CTRL_AXI_BURST_16 (0xf << 12) + +#define CIF_INTEN_FRAME_END_EN BIT(0) +#define CIF_INTEN_LINE_ERR_EN BIT(2) +#define CIF_INTEN_BUS_ERR_EN BIT(6) +#define CIF_INTEN_SCL_ERR_EN BIT(7) +#define CIF_INTEN_PST_INF_FRAME_END_EN BIT(9) + +#define CIF_INTSTAT_CLS 0x3ff +#define CIF_INTSTAT_FRAME_END BIT(0) +#define CIF_INTSTAT_LINE_END BIT(1) +#define CIF_INTSTAT_LINE_ERR BIT(2) +#define CIF_INTSTAT_PIX_ERR BIT(3) +#define CIF_INTSTAT_DFIFO_OF BIT(5) +#define CIF_INTSTAT_BUS_ERR BIT(6) +#define CIF_INTSTAT_PRE_INF_FRAME_END BIT(8) +#define CIF_INTSTAT_PST_INF_FRAME_END BIT(9) +#define CIF_INTSTAT_FRAME_END_CLR BIT(0) +#define CIF_INTSTAT_LINE_END_CLR BIT(1) +#define CIF_INTSTAT_LINE_ERR_CLR BIT(2) +#define CIF_INTSTAT_PST_INF_FRAME_END_CLR BIT(9) +#define CIF_INTSTAT_ERR 0xfc + +#define CIF_FRAME_STAT_CLS 0x00 +#define CIF_FRAME_FRM0_STAT_CLS 0x20 + +#define CIF_FORMAT_VSY_HIGH_ACTIVE BIT(0) +#define CIF_FORMAT_HSY_LOW_ACTIVE BIT(1) + +#define CIF_FORMAT_INPUT_MODE_YUV (0x00 << 2) +#define CIF_FORMAT_INPUT_MODE_PAL (0x02 << 2) +#define CIF_FORMAT_INPUT_MODE_NTSC (0x03 << 2) +#define CIF_FORMAT_INPUT_MODE_BT1120 (0x07 << 2) +#define CIF_FORMAT_INPUT_MODE_RAW (0x04 << 2) +#define CIF_FORMAT_INPUT_MODE_JPEG (0x05 << 2) +#define CIF_FORMAT_INPUT_MODE_MIPI (0x06 << 2) + +#define CIF_FORMAT_YUV_INPUT_ORDER_UYVY (0x00 << 5) +#define CIF_FORMAT_YUV_INPUT_ORDER_YVYU BIT(5) +#define CIF_FORMAT_YUV_INPUT_ORDER_VYUY BIT(6) +#define CIF_FORMAT_YUV_INPUT_ORDER_YUYV (0x03 << 5) +#define CIF_FORMAT_YUV_INPUT_422 (0x00 << 7) +#define CIF_FORMAT_YUV_INPUT_420 BIT(7) + +#define CIF_FORMAT_INPUT_420_ORDER_ODD BIT(8) + +#define CIF_FORMAT_CCIR_INPUT_ORDER_EVEN BIT(9) + +#define CIF_FORMAT_RAW_DATA_WIDTH_8 (0x00 << 11) +#define CIF_FORMAT_RAW_DATA_WIDTH_10 BIT(11) +#define CIF_FORMAT_RAW_DATA_WIDTH_12 (0x02 << 11) + +#define CIF_FORMAT_YUV_OUTPUT_422 (0x00 << 16) +#define CIF_FORMAT_YUV_OUTPUT_420 BIT(16) + +#define CIF_FORMAT_OUTPUT_420_ORDER_EVEN (0x00 << 17) +#define CIF_FORMAT_OUTPUT_420_ORDER_ODD BIT(17) + +#define CIF_FORMAT_RAWD_DATA_LITTLE_ENDIAN (0x00 << 18) +#define CIF_FORMAT_RAWD_DATA_BIG_ENDIAN BIT(18) + +#define CIF_FORMAT_UV_STORAGE_ORDER_UVUV (0x00 << 19) +#define CIF_FORMAT_UV_STORAGE_ORDER_VUVU BIT(19) + +#define CIF_FORMAT_BT1120_CLOCK_SINGLE_EDGES (0x00 << 24) +#define CIF_FORMAT_BT1120_CLOCK_DOUBLE_EDGES BIT(24) +#define CIF_FORMAT_BT1120_TRANSMIT_INTERFACE (0x00 << 25) +#define CIF_FORMAT_BT1120_TRANSMIT_PROGRESS BIT(25) +#define CIF_FORMAT_BT1120_YC_SWAP BIT(26) + +#define CIF_SCL_CTRL_ENABLE_SCL_DOWN BIT(0) +#define CIF_SCL_CTRL_ENABLE_SCL_UP BIT(1) +#define CIF_SCL_CTRL_ENABLE_YUV_16BIT_BYPASS BIT(4) +#define CIF_SCL_CTRL_ENABLE_RAW_16BIT_BYPASS BIT(5) +#define CIF_SCL_CTRL_ENABLE_32BIT_BYPASS BIT(6) +#define CIF_SCL_CTRL_DISABLE_32BIT_BYPASS (0x00 << 6) + +#define CIF_INTSTAT_F0_READY BIT(0) +#define CIF_INTSTAT_F1_READY BIT(1) + +#define CIF_CROP_Y_SHIFT 16 +#define CIF_CROP_X_SHIFT 0 + +#endif From patchwork Sun Feb 11 19:03:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mehdi Djait X-Patchwork-Id: 199507 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:50ea:b0:106:860b:bbdd with SMTP id r10csp2064988dyd; Sun, 11 Feb 2024 11:04:47 -0800 (PST) X-Google-Smtp-Source: AGHT+IE8TPPp0zBgrwSRoOaLF6iCqeLamvZO+bNMKJi5pFp7Qi1T7lm05RW4y1LZYpC5Rd8fJK+K X-Received: by 2002:a17:906:cf89:b0:a36:fc15:d724 with SMTP id um9-20020a170906cf8900b00a36fc15d724mr3497815ejb.18.1707678286716; Sun, 11 Feb 2024 11:04:46 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1707678286; cv=pass; d=google.com; s=arc-20160816; b=L/rrh561jVX8+S6Sj/VyI02ulL71z1TedASjsuBt447H6+NcU0BNdEgn3Cf1FP4hLX qftOXx+4uPZz0Sb+JozIH0n5+klhzJ9ZN5V+hn3UeOCsMUsZV/70vmjgJo0kigeRMu6o fId3EgCDlNMYPYH1Qqdp3e7iww/RJnxnZfrP2EqzSweXIxZotanVZp4IefCNj8xAXZDG 0CUvBHniZJ/fa5CfvBq4IsfLKbKQCA4KjLFxZNNGu3UeDfzWJykhL3ccYcZrIZ3JYzF9 pFRmN9uSOKyOTNfBgi4xOp67vnxXX9+agcavveqgQMOSrMJ+8ySwvE3zUkk6+rsE2W15 bA7Q== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=4X9gXtJ2jH9YgV610FJCPLMZwxMN7PK1ETxRA0Am1hs=; fh=w1yZqqPdDtLsU6v7jb53JQeAdDePCnbY4Whf1jCfErU=; b=gx6yq4El8cdD8wligroDwwHYlnnNeKhV6y0dvaX0i/BlGIf+2UhJWFl3I1ociP95Pe +yZDg0tVaNh5BIQpSpH8I9oYlZkDaIc8zMM+y4sc7bSb4fo9GT5bQw/sFlE8m2ZzwT0d jQc4oD87r+0x1v9y3qQzQhfDOtlajP1vAoz4dBg06mzQuo5A2T9Z6uNykrqL3CgZ5g/D cVxHgcnn2u2bb/yyOHIiUShnOj3LntrMMXSTWj/CHy9lt6ebbQa4mraN+Or69DJSctHE LI6od1q/13Cb2B39llbUMdDUcUhfUb47q8CyWkAVKo7h11rjJr7fkFkNmzIS2Ug5h8AS M0qQ==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=cIRojGTl; arc=pass (i=1 spf=pass spfdomain=gmail.com dkim=pass dkdomain=gmail.com dmarc=pass fromdomain=gmail.com); spf=pass (google.com: domain of linux-kernel+bounces-60921-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-60921-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com X-Forwarded-Encrypted: i=2; AJvYcCX2QIkQqHdi9qnsYhojRUZ0E917ifRhExZRar0ojFq8fOe4EXtwKt0l7Zs/dJEWwQneBVGB6DMSrTwbYu273l0QLxkRwQ== Received: from am.mirrors.kernel.org (am.mirrors.kernel.org. [2604:1380:4601:e00::3]) by mx.google.com with ESMTPS id e14-20020a1709062c0e00b00a23619be213si3178025ejh.159.2024.02.11.11.04.46 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 11 Feb 2024 11:04:46 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-60921-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) client-ip=2604:1380:4601:e00::3; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=cIRojGTl; arc=pass (i=1 spf=pass spfdomain=gmail.com dkim=pass dkdomain=gmail.com dmarc=pass fromdomain=gmail.com); spf=pass (google.com: domain of linux-kernel+bounces-60921-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-60921-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id 559411F20FCD for ; Sun, 11 Feb 2024 19:04:46 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 4044A5F473; Sun, 11 Feb 2024 19:03:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="cIRojGTl" Received: from mail-ej1-f44.google.com (mail-ej1-f44.google.com [209.85.218.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D06875E3A0; Sun, 11 Feb 2024 19:03:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707678228; cv=none; b=N3eFln3mRdXWj+iw2yn3qKIn7UnRPYSFeTCfaFRgYR4ULcgj8NDQY6k7GZV+QPUzHVZy4gL+T9cmHWxLwNULxi0KcTiLx4ZIC23UUUATa10dnAgNmZ5pooKISyqbDcHgXEno0+4WHbRTnKG3hVRTWZceJ0Dt2a7QTkEWvn28Lg8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707678228; c=relaxed/simple; bh=R8nbQPilcuK/zTa/Qd5mtxOQqvhrM5GRqlCnYSJHc+A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uT2Z288QwttQquDb8jt5Y8qarFGNdREWhCcx6vJA+vUwyd4Zhnh6Dgqao+HaLClKBClHAUzJr3kL3v6ywCNF82AIqrKEiARZyXFSMYvCaiTF20ThyYYZfelIqYWe8GXGMMWEVCv5hllEWQ0jDoRlQB3gGCK/qAnCYZZfR58eVK4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=cIRojGTl; arc=none smtp.client-ip=209.85.218.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ej1-f44.google.com with SMTP id a640c23a62f3a-a293f2280c7so352520966b.1; Sun, 11 Feb 2024 11:03:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1707678225; x=1708283025; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=4X9gXtJ2jH9YgV610FJCPLMZwxMN7PK1ETxRA0Am1hs=; b=cIRojGTlU6To90/T0kqNYQjmXXNXtjL8a+nZB4UHzfYKgEF3duf0ydJbfv0Nu2sNqc X3R19QEq6EKHpWxiF8gAY2jQSeqGREQTLWWBiWVz0HyYMFb3MCDzkYvheNBhc1+EUZMA ESP25u97V/1/NQhI3Ea4B4WeLf71uF6xz+yngJS8byhY9Nh5i9o4D0k07fV2o6MQBRrf 1m4xoqRIiU/iQk1W+EyajKeZHY6SxWZ9KUWQS83M+ESGCBczN4em9mJtrNK8F1aAYc+4 L/i1Yz5Q1X+lpmRJMRoNPaUjcWVGq0KJDtyOsKhrEaEXuzeEefsDJtfSrFEKWHNRbeZZ MQTg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1707678225; x=1708283025; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=4X9gXtJ2jH9YgV610FJCPLMZwxMN7PK1ETxRA0Am1hs=; b=aBYgRU4pW/aiy2lGRrs3EVXrriqZofrEiEJt7DCYfVSoCoXGeCypg875cD5XrH/u1F Woh0tOpYaSIpqu304otKVYR8Q3hHQo+m9ml0fLtWSENIaAQ+S91IiZx22JxWGp5gTz10 itJFcqiasXiTUgx+TlWjeiLoBvil7wXF7Wk4jz45mdO4s+K7xwpfqSF9fRb6af2CI03O SoSGhEP5f0IhcBoBUmJfmypeKJzEDThEFeRfgEs9cUzRlulYH0kQtZ09H4QDDezcN2uU wk50NnJLK3b3oS7MsaocOXYs7mgobXgRZ/QKuxRjy4Vd7ea/AQKAgXTtHs3X2kyYbQaU J12A== X-Gm-Message-State: AOJu0Yw/3p57dCc/0GGnyPb2Kmz4BvR5HcTp6G9mRZHWplddudsjFd8+ 7NGSVjWi69kxvlxFx25LXla9Oxfg2IW4xCdnbf1Qc4Myy9VbSUrU X-Received: by 2002:a17:906:3596:b0:a3b:acdb:4922 with SMTP id o22-20020a170906359600b00a3bacdb4922mr3451279ejb.8.1707678224766; Sun, 11 Feb 2024 11:03:44 -0800 (PST) X-Forwarded-Encrypted: i=1; AJvYcCVqqngmGLbiOIGazXprKf+BgTCIh2Ak/6mUEwc2g7kDFfShRBGwlquhYhyBpik6jjhNUJJPBAxke8mnNmTg+PlaArkAShRxOqARChCITho8kM3r8Aml8yq+uAwqIwAwsbiz9mN7nIVQXf5xtwA1XmKcBCHtXWlsK0kvbcvyA0x8/jj+CUPMOC1AZJNHwDMty8FHdqJ+x7U12yY/TIsToOI3C2z+nRR9MZO1Wt36yrPZtrwYPpQwp7ndXkRQqHRSmUCu1dty6KXXBVg5KKTrL7k64x02mFW9xp5DvM9mAnOaJzYGx9f7dgMOAf3Ux8OIeeCArBpLnpH7103xJCeCU+kOlk34qA9BFOjdpk+ywmvU0Pl9WTkBqexSkKhKPxtAREJRDRRx+HNXe9aApt2GpSl+Vekz1rLYG3b60Jx+SKRIHFpqoMC7Au+YnaGPiBh/nT8vwFsoDSElGcBdDm7F+8qkcW59tZeSmVAukj4P3odlQ6whspxLQCDU1a6+X2gfl3BwoX8rG+SZyjufSFRBjylnzHxmDw76Ylz/epwfCtqXQwEFjIOrx48wNTbFvRi61HwjAXftjrOlgwzZNyoKdSd6p5Ho/yZb6GGwC0qyGzY= Received: from localhost.localdomain ([2a02:8109:aa27:2d00::2d2b]) by smtp.gmail.com with ESMTPSA id ps7-20020a170906bf4700b00a3c5fa1052csm1207400ejb.138.2024.02.11.11.03.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 11 Feb 2024 11:03:44 -0800 (PST) From: Mehdi Djait To: mchehab@kernel.org, heiko@sntech.de, hverkuil-cisco@xs4all.nl, krzysztof.kozlowski+dt@linaro.org, robh+dt@kernel.org, conor+dt@kernel.org Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, alexandre.belloni@bootlin.com, maxime.chevallier@bootlin.com, paul.kocialkowski@bootlin.com, michael.riesch@wolfvision.net, laurent.pinchart@ideasonboard.com, Mehdi Djait , Mehdi Djait Subject: [RESEND Patch v13 3/3] arm64: dts: rockchip: Add the px30 camera interface Date: Sun, 11 Feb 2024 20:03:32 +0100 Message-ID: X-Mailer: git-send-email 2.43.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1790630466948586385 X-GMAIL-MSGID: 1790630466948586385 From: Mehdi Djait The px30 has a video capture component, supporting the BT.656 parallel interface. Add a DT description for it. Reviewed-by: Michael Riesch Reviewed-by: Paul Kocialkowski Signed-off-by: Mehdi Djait Signed-off-by: Mehdi Djait --- arch/arm64/boot/dts/rockchip/px30.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/px30.dtsi b/arch/arm64/boot/dts/rockchip/px30.dtsi index d0905515399b..a8eb5371235b 100644 --- a/arch/arm64/boot/dts/rockchip/px30.dtsi +++ b/arch/arm64/boot/dts/rockchip/px30.dtsi @@ -1280,6 +1280,18 @@ isp_mmu: iommu@ff4a8000 { #iommu-cells = <0>; }; + cif: video-capture@ff490000 { + compatible = "rockchip,px30-vip"; + reg = <0x0 0xff490000 0x0 0x200>; + interrupts = ; + clocks = <&cru ACLK_CIF>, <&cru HCLK_CIF>, <&cru PCLK_CIF>; + clock-names = "aclk", "hclk", "pclk"; + power-domains = <&power PX30_PD_VI>; + resets = <&cru SRST_CIF_A>, <&cru SRST_CIF_H>, <&cru SRST_CIF_PCLKIN>; + reset-names = "axi", "ahb", "pclkin"; + status = "disabled"; + }; + qos_gmac: qos@ff518000 { compatible = "rockchip,px30-qos", "syscon"; reg = <0x0 0xff518000 0x0 0x20>;