From patchwork Wed Dec 14 09:26:30 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marvin Lin X-Patchwork-Id: 13072899 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 7F714C001B2 for ; Wed, 14 Dec 2022 09:27:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237744AbiLNJ1y (ORCPT ); Wed, 14 Dec 2022 04:27:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40872 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237718AbiLNJ10 (ORCPT ); Wed, 14 Dec 2022 04:27:26 -0500 Received: from mail-pf1-x42c.google.com (mail-pf1-x42c.google.com [IPv6:2607:f8b0:4864:20::42c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AA17F21832; Wed, 14 Dec 2022 01:27:25 -0800 (PST) Received: by mail-pf1-x42c.google.com with SMTP id 65so4015093pfx.9; Wed, 14 Dec 2022 01:27:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; 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=1v2Hnzs0/1OJywqxGltmBJ3aGPcFLQM/mVyL2AkPibQ=; b=NNgZuapkeFk7n59ulBy0O32WFNBp51TE995pPuOgE5QJLoqrWkOWVFtoV5scKn5e3Z xaqMVhVK0LxpFgCi5MaTO43wQhauSWct2uGbH9U6GmNajOh2Ks/eLc2eJ07xU428Laz8 m+nbaGm5wOee7OvVfeSnJ+mCSiFTuOgUk0vZ2Y1+XBsfrD2KoX/+xdTx9T5UunowER3F IgB2mqs/186mc7EHSnxk1TcLtJcd8Gm4wk/jURQK+ytRyfFmRzvCcx9Z6OcnID3YlyQG U/9A/b2GmceDvWkgwbJkK8Zj8WhiHN9UyujlRmb2tFE0aRhjQAy3b7Ql6BujngFF0xCz gHbw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=1v2Hnzs0/1OJywqxGltmBJ3aGPcFLQM/mVyL2AkPibQ=; b=nyU8ThtRStbM3CzKOnXGXMAkzSSwkf+dzpv0GHvucRQURxlcIv/ZqmkePjGdjV8NqR ZNbJBo7/nXoAkvMj/rfIKDhIwcOtqMP2BilouT/4KqzF7pv3qw5eG0LUi4tIxv+K6wiH AfeuTCLrpClaPAf5zlJh2agKvpaQoiT8pjU/fvSeTTWJ7qPB8k7vHCT+0WEwNdUM3xKO MTbdPxZdQ9NPcFSMkKItzrZUbb1/QUpSDRQQ6B1iYWGICkNzza93UYwxn8OfjnhCvHn5 2s7qQN/2P8s66ide45Wp1/N8P5n4o6dBfUk0E/1iYb1DWcU5NiMDWUpmALjLN+eeNFC4 CzVA== X-Gm-Message-State: ANoB5plW/LNIofGJGVQYpqUd+mzJUOoNtJENxrcFDQ7/0q/US0ODJqYi 17iI5CgG2BzuxXFQ79Bwym4= X-Google-Smtp-Source: AA0mqf5hhWMvTBEcxBKuAav1yFJesn4l75sw28A1sQknb8ihHWqlvJvBB5lLwUGOIS0SFCHTbQvbgQ== X-Received: by 2002:aa7:9810:0:b0:577:1553:9241 with SMTP id e16-20020aa79810000000b0057715539241mr27771275pfl.17.1671010045184; Wed, 14 Dec 2022 01:27:25 -0800 (PST) Received: from hcdev-d520mt2.. (60-250-192-107.hinet-ip.hinet.net. [60.250.192.107]) by smtp.gmail.com with ESMTPSA id t123-20020a628181000000b00576145a9bd0sm9003312pfd.127.2022.12.14.01.27.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 14 Dec 2022 01:27:24 -0800 (PST) From: Marvin Lin To: mchehab@kernel.org, linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org Cc: openbmc@lists.ozlabs.org, avifishman70@gmail.com, tmaimon77@gmail.com, tali.perry1@gmail.com, venture@google.com, yuenn@google.com, benjaminfair@google.com, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, kwliu@nuvoton.com, kflin@nuvoton.com, Marvin Lin Subject: [PATCH v8 1/7] ARM: dts: nuvoton: Add node for NPCM VCD and ECE engine Date: Wed, 14 Dec 2022 17:26:30 +0800 Message-Id: <20221214092636.810883-2-milkfafa@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20221214092636.810883-1-milkfafa@gmail.com> References: <20221214092636.810883-1-milkfafa@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Add node for Video Capture/Differentiation Engine (VCD) and Encoding Compression Engine (ECE) present on Nuvoton NPCM SoCs. Tested with Nuvoton NPCM750 evaluation board. Signed-off-by: Marvin Lin --- arch/arm/boot/dts/nuvoton-common-npcm7xx.dtsi | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/arm/boot/dts/nuvoton-common-npcm7xx.dtsi b/arch/arm/boot/dts/nuvoton-common-npcm7xx.dtsi index c7b5ef15b716..78a309a56cd5 100644 --- a/arch/arm/boot/dts/nuvoton-common-npcm7xx.dtsi +++ b/arch/arm/boot/dts/nuvoton-common-npcm7xx.dtsi @@ -179,6 +179,24 @@ fiux: spi@fb001000 { status = "disabled"; }; + vcd: vcd@f0810000 { + compatible = "nuvoton,npcm750-vcd"; + reg = <0xf0810000 0x10000>; + interrupts = ; + resets = <&rstc NPCM7XX_RESET_IPSRST2 NPCM7XX_RESET_VCD>; + nuvoton,sysgcr = <&gcr>; + nuvoton,sysgfxi = <&gfxi>; + nuvoton,ece = <&ece>; + status = "disabled"; + }; + + ece: ece@f0820000 { + compatible = "nuvoton,npcm750-ece"; + reg = <0xf0820000 0x2000>; + resets = <&rstc NPCM7XX_RESET_IPSRST2 NPCM7XX_RESET_ECE>; + status = "disabled"; + }; + apb { #address-cells = <1>; #size-cells = <1>; @@ -554,6 +572,11 @@ i2c15: i2c@8f000 { pinctrl-0 = <&smb15_pins>; status = "disabled"; }; + + gfxi: gfxi@e000 { + compatible = "nuvoton,npcm750-gfxi", "syscon"; + reg = <0xe000 0x100>; + }; }; }; From patchwork Wed Dec 14 09:26:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marvin Lin X-Patchwork-Id: 13072901 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 AC21CC4167B for ; Wed, 14 Dec 2022 09:28:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237713AbiLNJ16 (ORCPT ); Wed, 14 Dec 2022 04:27:58 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40062 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229867AbiLNJ13 (ORCPT ); Wed, 14 Dec 2022 04:27:29 -0500 Received: from mail-pg1-x534.google.com (mail-pg1-x534.google.com [IPv6:2607:f8b0:4864:20::534]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 98FA21EC74; Wed, 14 Dec 2022 01:27:28 -0800 (PST) Received: by mail-pg1-x534.google.com with SMTP id s196so1586809pgs.3; Wed, 14 Dec 2022 01:27:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; 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=mX/uA7dWiRKXelGChnYmrQLN0BiYwtLQQDjw/Nwye6g=; b=ZVrm7SGtB67IjlLwP27xUEnqkJDF8vDYaiFopITwz5t0Ha4ep7CUdAfJ7SZvMGvNlZ I/yJKUMl0HQ6NfWQK0AH3OhXA0DCY/HSU6NrnVRmOWbENw6B6d2jQ6zs9Ip+Y7I2oqX3 LZ9HPKH7TmAYQLMlqyJu+aEHfi4UZm//O8Iqe5LM9gHpGabRBD6WyVhn+Q0Hfm3uk3eF stjFbgTTXzoe0g/nhFd6WojJSJxDDJH0DYlCwxJC6G2KHtB3CTbXy67i74QsCASfTBd2 rPJKpjk7NPq5QJibDJ3OWfhfcAUXmmKnInuALjliC7Em4yWeEYS2teesz0iNV3HByaIv Evzw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=mX/uA7dWiRKXelGChnYmrQLN0BiYwtLQQDjw/Nwye6g=; b=fDN0iTakACtTXK/xAKmgOLC/FAueHKxvcT3gk+LCruvksYRFRx77wNPVy7VwNiOkGT VgLyETB1XqxE9SVtX68JlAcoLcIJQKmyeJuC/qjXfFLQ1EoP7zVYfTLOpJhNMMbt+ZcC Ypzjbui6Q/AIL/U4qFrUw/aDdEmz9dX1Ir5tI1GmOlo4sDjJN3InrCs7skyfw+C8viJ+ hD/P278ry7Sd1+IsCBRmXt5oj0AVH+7USbxnkVD+jO8ofOdSULnyZEhTURG9Orpu5NUf w0n9+NiBvpYo/4fxKqwLq56V8KorheeLCRwYiVW6wdK/d+PXblKs8yOqf2c2mmbgGryn 7PUA== X-Gm-Message-State: ANoB5pkUJIDrVLRzslkRZ138WwhSgNB9uhPeIGv7T1fjlxsZ+BbYiFjg RwJO1TxN0VIEE0RjlOgr0Ys= X-Google-Smtp-Source: AA0mqf5qmSIqFDAPfxCCbH3WB/HmilnBhUGbUyRyLe5tlV3japgFI/iGhZW19kAfvjepl9J4a2pSsQ== X-Received: by 2002:a62:640f:0:b0:574:f1bc:bbee with SMTP id y15-20020a62640f000000b00574f1bcbbeemr21158111pfb.31.1671010048087; Wed, 14 Dec 2022 01:27:28 -0800 (PST) Received: from hcdev-d520mt2.. (60-250-192-107.hinet-ip.hinet.net. [60.250.192.107]) by smtp.gmail.com with ESMTPSA id t123-20020a628181000000b00576145a9bd0sm9003312pfd.127.2022.12.14.01.27.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 14 Dec 2022 01:27:27 -0800 (PST) From: Marvin Lin To: mchehab@kernel.org, linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org Cc: openbmc@lists.ozlabs.org, avifishman70@gmail.com, tmaimon77@gmail.com, tali.perry1@gmail.com, venture@google.com, yuenn@google.com, benjaminfair@google.com, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, kwliu@nuvoton.com, kflin@nuvoton.com, Marvin Lin Subject: [PATCH v8 2/7] media: dt-binding: nuvoton: Add bindings for NPCM VCD and ECE engine Date: Wed, 14 Dec 2022 17:26:31 +0800 Message-Id: <20221214092636.810883-3-milkfafa@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20221214092636.810883-1-milkfafa@gmail.com> References: <20221214092636.810883-1-milkfafa@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Add dt-binding document for Video Capture/Differentiation Engine (VCD) and Encoding Compression Engine (ECE) present on Nuvoton NPCM SoCs. Signed-off-by: Marvin Lin --- .../bindings/media/nuvoton,npcm-ece.yaml | 44 ++++++++++++ .../bindings/media/nuvoton,npcm-vcd.yaml | 72 +++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/nuvoton,npcm-ece.yaml create mode 100644 Documentation/devicetree/bindings/media/nuvoton,npcm-vcd.yaml diff --git a/Documentation/devicetree/bindings/media/nuvoton,npcm-ece.yaml b/Documentation/devicetree/bindings/media/nuvoton,npcm-ece.yaml new file mode 100644 index 000000000000..d12b76d137d9 --- /dev/null +++ b/Documentation/devicetree/bindings/media/nuvoton,npcm-ece.yaml @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/nuvoton,npcm-ece.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nuvoton NPCM Encoding Compression Engine + +maintainers: + - Joseph Liu + - Marvin Lin + +description: | + Video Encoding Compression Engine (ECE) present on Nuvoton NPCM SoCs. + +properties: + compatible: + enum: + - nuvoton,npcm750-ece + - nuvoton,npcm845-ece + + reg: + maxItems: 1 + + resets: + maxItems: 1 + +required: + - compatible + - reg + - resets + +additionalProperties: false + +examples: + - | + #include + + ece: ece@f0820000 { + compatible = "nuvoton,npcm750-ece"; + reg = <0xf0820000 0x2000>; + resets = <&rstc NPCM7XX_RESET_IPSRST2 NPCM7XX_RESET_ECE>; + }; diff --git a/Documentation/devicetree/bindings/media/nuvoton,npcm-vcd.yaml b/Documentation/devicetree/bindings/media/nuvoton,npcm-vcd.yaml new file mode 100644 index 000000000000..2d8da8f36506 --- /dev/null +++ b/Documentation/devicetree/bindings/media/nuvoton,npcm-vcd.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/nuvoton,npcm-vcd.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nuvoton NPCM Video Capture/Differentiation Engine + +maintainers: + - Joseph Liu + - Marvin Lin + +description: | + Video Capture/Differentiation Engine (VCD) present on Nuvoton NPCM SoCs. + +properties: + compatible: + enum: + - nuvoton,npcm750-vcd + - nuvoton,npcm845-vcd + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + resets: + maxItems: 1 + + nuvoton,sysgcr: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle to access GCR (Global Control Register) registers. + + nuvoton,sysgfxi: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle to access GFXI (Graphics Core Information) registers. + + nuvoton,ece: + $ref: /schemas/types.yaml#/definitions/phandle + description: phandle to access ECE (Encoding Compression Engine) registers. + + memory-region: + description: + CMA pool to use for buffers allocation instead of the default CMA pool. + +required: + - compatible + - reg + - interrupts + - resets + - nuvoton,sysgcr + - nuvoton,sysgfxi + - nuvoton,ece + +additionalProperties: false + +examples: + - | + #include + #include + + vcd: vcd@f0810000 { + compatible = "nuvoton,npcm750-vcd"; + reg = <0xf0810000 0x10000>; + interrupts = ; + resets = <&rstc NPCM7XX_RESET_IPSRST2 NPCM7XX_RESET_VCD>; + nuvoton,sysgcr = <&gcr>; + nuvoton,sysgfxi = <&gfxi>; + nuvoton,ece = <&ece>; + }; From patchwork Wed Dec 14 09:26:32 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marvin Lin X-Patchwork-Id: 13072900 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 644A9C4332F for ; Wed, 14 Dec 2022 09:27:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237754AbiLNJ14 (ORCPT ); Wed, 14 Dec 2022 04:27:56 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40070 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237668AbiLNJ1c (ORCPT ); Wed, 14 Dec 2022 04:27:32 -0500 Received: from mail-pg1-x535.google.com (mail-pg1-x535.google.com [IPv6:2607:f8b0:4864:20::535]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8742421836; Wed, 14 Dec 2022 01:27:31 -0800 (PST) Received: by mail-pg1-x535.google.com with SMTP id f9so1574315pgf.7; Wed, 14 Dec 2022 01:27:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; 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=6oDp0Y4hNKtuwWRzIl64XHBZWtkU1cebMe5ez5uOfwA=; b=pqjQzeUx5dqr1YIv0SnnHz+AquJUATPTy0QMtyTeqzG9ciXi8VFJ36NfszsDd0V3cM S1Z4RoLH7CDUhblnqxpNSMLEqp6SRFAA5uu1JPb3qjdY5OxzAQBfhjna8Tme/vakjNIa GpkLzn8VdJTC4/jTDayDwPJ2zCsAUkhupMRswh9l2IyKDZE822VrJyTtmC8HVuoXBBJJ J/wFRyXOb/HueYi4BZ+OuW8J8j5hOb3dw6OBKHVDlfe7oGqwqu04h6a4Yef3Sp1xRXE5 yMUrXJ64S0KIQ7PVo5r9fTcqYa2bFHH3r6121GniS/820+VBXcLZeNYBz2c1E/7kTS+y u7Hw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=6oDp0Y4hNKtuwWRzIl64XHBZWtkU1cebMe5ez5uOfwA=; b=Ezp5ogl5DPSCk/AVw5xYdqiLTIL8pq+4aRUmATgzM7fYywWFD5tYrQ92Ix6CZFR0pq GZd59CQvbp7mWi6EqBpccQM5PLAzuEJsyCXJlQnsHvR+Fm70rarJVHvzB6MugfnzCDrF I3rz8vlaxKI71uNYfBPE4y1Fs5av0nbHc80YAsm+ySdaO1T9Ej83OMe5m3osRrxqTxfH dKiMtnkuEwSIRSKMaxC5mG446zUj2mCXROnLNIiKf7pP/qrDaaomQ4aw91dhxVSstTQy TZiQI3XApJ1ANKvyxBvui5s1xJVcHULefS+2ClxqJ5Ply/ipKhAF80qi8Z6ZVXnFraPw goVw== X-Gm-Message-State: ANoB5pnkG8hWpwuMRxnIu2UnY8YZle/MHtIjCbNPALH6xEOvBQKgDpJj 3j0JXFN6b2hfs+KM5EfDGgA= X-Google-Smtp-Source: AA0mqf7/dk4aWxX6iQbCbpBPPdJL/vG217lPXQbhmyLUP9sqy+fuXL1uh2qQphzUnvPObHLbPRZFfw== X-Received: by 2002:aa7:83d7:0:b0:56c:cde:1a44 with SMTP id j23-20020aa783d7000000b0056c0cde1a44mr20623117pfn.11.1671010051011; Wed, 14 Dec 2022 01:27:31 -0800 (PST) Received: from hcdev-d520mt2.. (60-250-192-107.hinet-ip.hinet.net. [60.250.192.107]) by smtp.gmail.com with ESMTPSA id t123-20020a628181000000b00576145a9bd0sm9003312pfd.127.2022.12.14.01.27.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 14 Dec 2022 01:27:30 -0800 (PST) From: Marvin Lin To: mchehab@kernel.org, linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org Cc: openbmc@lists.ozlabs.org, avifishman70@gmail.com, tmaimon77@gmail.com, tali.perry1@gmail.com, venture@google.com, yuenn@google.com, benjaminfair@google.com, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, kwliu@nuvoton.com, kflin@nuvoton.com, Marvin Lin Subject: [PATCH v8 3/7] dt-bindings: arm: nuvoton: Add bindings for NPCM GFXI Date: Wed, 14 Dec 2022 17:26:32 +0800 Message-Id: <20221214092636.810883-4-milkfafa@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20221214092636.810883-1-milkfafa@gmail.com> References: <20221214092636.810883-1-milkfafa@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Add dt-bindings document for Graphics Core Information (GFXI) node. It is used by NPCM video driver to retrieve Graphics core information. Signed-off-by: Marvin Lin Reviewed-by: Krzysztof Kozlowski --- .../bindings/arm/npcm/nuvoton,gfxi.yaml | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/npcm/nuvoton,gfxi.yaml diff --git a/Documentation/devicetree/bindings/arm/npcm/nuvoton,gfxi.yaml b/Documentation/devicetree/bindings/arm/npcm/nuvoton,gfxi.yaml new file mode 100644 index 000000000000..7c8e5f99cc50 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/npcm/nuvoton,gfxi.yaml @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/npcm/nuvoton,gfxi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Graphics Core Information block in Nuvoton SoCs + +maintainers: + - Joseph Liu + - Marvin Lin + +description: + The Graphics Core Information (GFXI) are a block of registers in Nuvoton SoCs + that analyzes Graphics core behavior and provides information in registers. + +properties: + compatible: + items: + - enum: + - nuvoton,npcm750-gfxi + - nuvoton,npcm845-gfxi + - const: syscon + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + gfxi: gfxi@e000 { + compatible = "nuvoton,npcm750-gfxi", "syscon"; + reg = <0xe000 0x100>; + }; From patchwork Wed Dec 14 09:26:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marvin Lin X-Patchwork-Id: 13072902 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 6012AC4332F for ; Wed, 14 Dec 2022 09:28:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237392AbiLNJ2B (ORCPT ); Wed, 14 Dec 2022 04:28:01 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40978 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237752AbiLNJ1f (ORCPT ); Wed, 14 Dec 2022 04:27:35 -0500 Received: from mail-pg1-x52c.google.com (mail-pg1-x52c.google.com [IPv6:2607:f8b0:4864:20::52c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 90A6F1D648; Wed, 14 Dec 2022 01:27:34 -0800 (PST) Received: by mail-pg1-x52c.google.com with SMTP id 82so1615104pgc.0; Wed, 14 Dec 2022 01:27:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; 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=g/uLvTJmmBzuds9Az0fvihrnUknv2MS6FQWlRinADjY=; b=Xc7Aw+e3WI6qp/eJxVFeHPJhPyxAmfIvPUnKDh5B15XKFHr0Pfq4efdEqjCMJT0gPL UA9KG3U5S7MVLlvwHlpT1LvnKMkRV57gq6i3WFULyjbqp9mPb/Cf3kSbNObOnOLDESgh hQVe5rBJUST+ttJnd6LGy8yUVoGUHiyewoDHGsO8GpSBIK70JnnmwKJrHr+eK6vu74hI wH/Gl/O1v0x6VkEn7eqCmbNuizi2QQVWLuEYOkgSQfRU4umTecoIx4aejaHSwLTmp/Pn FXaHqpX7hcS+ywx7kAVbSN0rABFE6P8UbeKCon8iix3BVpFYhtQUo/aB1qW0VXHPsZQb PBNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=g/uLvTJmmBzuds9Az0fvihrnUknv2MS6FQWlRinADjY=; b=dhx5YUE9P2WwBs2rJ7p4IlWqIiUJbwksRbOoPWJ02LGWo2edy1prXBmb82s4orlo8R 17ugSteq2HHMuiapPvT75sCYRjMZW84Wkl8F9LeAQ2OlSV41lLl3YK1mmZ1iih/5xGB2 YvyXt6qjrn+8Q6Gi1bzk+dN0I+rXBDcuBI0qhHwv9X2nW16NvDs6Dt5Exb/LdZZ+I1XE l6afeZYQW7dfgoPal2OxWrXS0s+JlvwR2NfA+P99tqQJN6rvWl04rlEKWedbl1vkYEml vTdcFSSxmzIUqvmqYMumGu+WN8VA+j4YU6vQEAYvX88myrb3p9uFnQJR+Q+5qSpaUjmf xQYg== X-Gm-Message-State: ANoB5pk1yFI7E8hlsifqLJ1r7gs0p9fYw0rjwoKHVursNxvwXl1h89CB HccHKDC09JdwtZGm08JOB/o= X-Google-Smtp-Source: AA0mqf4v0xkpJREBw5ozMubrsIyFRAves3U8tUVkd0+5EMAmKWDlHBDmxuW+XcG7VAlZ0w+3ZlgF4w== X-Received: by 2002:a62:870d:0:b0:576:f02e:d0ef with SMTP id i13-20020a62870d000000b00576f02ed0efmr22903084pfe.4.1671010054037; Wed, 14 Dec 2022 01:27:34 -0800 (PST) Received: from hcdev-d520mt2.. (60-250-192-107.hinet-ip.hinet.net. [60.250.192.107]) by smtp.gmail.com with ESMTPSA id t123-20020a628181000000b00576145a9bd0sm9003312pfd.127.2022.12.14.01.27.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 14 Dec 2022 01:27:33 -0800 (PST) From: Marvin Lin To: mchehab@kernel.org, linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org Cc: openbmc@lists.ozlabs.org, avifishman70@gmail.com, tmaimon77@gmail.com, tali.perry1@gmail.com, venture@google.com, yuenn@google.com, benjaminfair@google.com, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, kwliu@nuvoton.com, kflin@nuvoton.com, Marvin Lin , Nicolas Dufresne Subject: [PATCH v8 4/7] media: v4l: Add HEXTILE compressed format Date: Wed, 14 Dec 2022 17:26:33 +0800 Message-Id: <20221214092636.810883-5-milkfafa@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20221214092636.810883-1-milkfafa@gmail.com> References: <20221214092636.810883-1-milkfafa@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Add HEXTILE compressed format which is defined in Remote Framebuffer Protocol (RFC 6143, chapter 7.7.4 Hextile Encoding) and is used by Encoding Compression Engine (ECE) present on Nuvoton NPCM SoCs. Signed-off-by: Marvin Lin Reviewed-by: Nicolas Dufresne --- Documentation/userspace-api/media/v4l/pixfmt-reserved.rst | 7 +++++++ drivers/media/v4l2-core/v4l2-ioctl.c | 1 + include/uapi/linux/videodev2.h | 1 + 3 files changed, 9 insertions(+) diff --git a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst index 73cd99828010..e6ee0eebe691 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-reserved.rst @@ -275,6 +275,13 @@ please make a proposal on the linux-media mailing list. Decoder's implementation can be found here, `aspeed_codec `__ + * .. _V4L2-PIX-FMT-HEXTILE: + + - ``V4L2_PIX_FMT_HEXTILE`` + - 'HXTL' + - Compressed format used by Nuvoton NPCM video driver. This format is + defined in Remote Framebuffer Protocol (RFC 6143, chapter 7.7.4 Hextile + Encoding). .. raw:: latex \normalsize diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 8e0a0ff62a70..a0e387335139 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1494,6 +1494,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_QC08C: descr = "QCOM Compressed 8-bit Format"; break; case V4L2_PIX_FMT_QC10C: descr = "QCOM Compressed 10-bit Format"; break; case V4L2_PIX_FMT_AJPG: descr = "Aspeed JPEG"; break; + case V4L2_PIX_FMT_HEXTILE: descr = "Hextile Compressed Format"; break; default: if (fmt->description[0]) return; diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 1befd181a4cc..1ce21cc4fbf1 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -778,6 +778,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_QC08C v4l2_fourcc('Q', '0', '8', 'C') /* Qualcomm 8-bit compressed */ #define V4L2_PIX_FMT_QC10C v4l2_fourcc('Q', '1', '0', 'C') /* Qualcomm 10-bit compressed */ #define V4L2_PIX_FMT_AJPG v4l2_fourcc('A', 'J', 'P', 'G') /* Aspeed JPEG */ +#define V4L2_PIX_FMT_HEXTILE v4l2_fourcc('H', 'X', 'T', 'L') /* Hextile compressed */ /* 10bit raw packed, 32 bytes for every 25 pixels, last LSB 6 bits unused */ #define V4L2_PIX_FMT_IPU3_SBGGR10 v4l2_fourcc('i', 'p', '3', 'b') /* IPU3 packed 10-bit BGGR bayer */ From patchwork Wed Dec 14 09:26:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marvin Lin X-Patchwork-Id: 13072903 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 A6523C10F1E for ; Wed, 14 Dec 2022 09:28:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237595AbiLNJ2D (ORCPT ); Wed, 14 Dec 2022 04:28:03 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41378 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237769AbiLNJ1j (ORCPT ); Wed, 14 Dec 2022 04:27:39 -0500 Received: from mail-pf1-x430.google.com (mail-pf1-x430.google.com [IPv6:2607:f8b0:4864:20::430]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7FD75B68; Wed, 14 Dec 2022 01:27:37 -0800 (PST) Received: by mail-pf1-x430.google.com with SMTP id c13so4024316pfp.5; Wed, 14 Dec 2022 01:27:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; 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=xLpWFlG8mxCCWcewzRCKKTz15AMme8ZuJhE5IEg3io0=; b=NdoF3cNFvXv/M3+aBr6oTDL01XCH53BB6efW2D9TwDjttKAN2fqd9wCLBFKRra84A8 076QSS5+5Xkj5xaxUarsRhRtVHABJncmznu2U7yewp0pYZlUZljVPRUnxYZnI6obuK3g ZCmexl3Z6dHEpdO9/o2XmBrO1JyHtwYi1Kh+ME7XqmY3qLukNNze0iwxNHOe9zMA2aqD gJlKq61sDR2PXffsV7tFOZT+2RsbzxzPJ3D+3SCpmmCwiWDIvdX29VXXCga/Z+ChheUE utTXUnbbIBPjlGonsBnxjcK5k+7DMC6OiMEmJedwF2A4GDcJt2t6dIVf1WuxDE/17eAC ygDw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=xLpWFlG8mxCCWcewzRCKKTz15AMme8ZuJhE5IEg3io0=; b=F5j09nHWltcdykcOFLwq8fA3Ts5DQdVwK7DZAgv6//fka4UluAqJbTzkw6T9NQwyd8 Oks5ZCIYEs62h1CtvE+/sHBI+SPv5bGr59oNFUM+mDD2myhh9MT5FAlMkbyxO6eE7wg/ tTaGLyEYFULbKHUS/TVpRNKecJn6bpZQ/ZCg4laCrcvO3F/5zuslqQN2FMUsBtiO31IG 5YUwZRNs7DR1RVlbiO2getorNBVgfuOkfmpYAizM5cSLQWSENCTbNg9Z5Q/zZBf9LdCq n/gQ/ADyhpC9UICP4SS8jWw4/UZmeFBgl83PIxHXCtYVupQnbDqtW4cz7AqL9/vnVXAS WKyA== X-Gm-Message-State: ANoB5plEUVYlqCiPKhiJs59Y7cZIaDEKqdFnr/MBgt5WshiIKqyWcwT3 pbEw6aJ1xQvDvLq8JM8S27Q= X-Google-Smtp-Source: AA0mqf4Ng4hlbOW8z0BGWKEyNXler717YQ1Fdr8pfObDXmNg3crKRtCmJj3s5c5PMKDUy7jCnC7gqA== X-Received: by 2002:aa7:9297:0:b0:573:f869:2115 with SMTP id j23-20020aa79297000000b00573f8692115mr21004739pfa.9.1671010057016; Wed, 14 Dec 2022 01:27:37 -0800 (PST) Received: from hcdev-d520mt2.. (60-250-192-107.hinet-ip.hinet.net. [60.250.192.107]) by smtp.gmail.com with ESMTPSA id t123-20020a628181000000b00576145a9bd0sm9003312pfd.127.2022.12.14.01.27.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 14 Dec 2022 01:27:36 -0800 (PST) From: Marvin Lin To: mchehab@kernel.org, linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org Cc: openbmc@lists.ozlabs.org, avifishman70@gmail.com, tmaimon77@gmail.com, tali.perry1@gmail.com, venture@google.com, yuenn@google.com, benjaminfair@google.com, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, kwliu@nuvoton.com, kflin@nuvoton.com, Marvin Lin Subject: [PATCH v8 5/7] media: v4l2-ctrls: Reserve user control base for NPCM video controls Date: Wed, 14 Dec 2022 17:26:34 +0800 Message-Id: <20221214092636.810883-6-milkfafa@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20221214092636.810883-1-milkfafa@gmail.com> References: <20221214092636.810883-1-milkfafa@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Add a control base and reserve 16 controls for Nuvoton NPCM video controls. Signed-off-by: Marvin Lin --- include/uapi/linux/v4l2-controls.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index b73a8ba7df6c..aa5c9f64f1d6 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -199,6 +199,12 @@ enum v4l2_colorfx { */ #define V4L2_CID_USER_ASPEED_BASE (V4L2_CID_USER_BASE + 0x11a0) +/* + * The base for Nuvoton NPCM driver controls. + * We reserve 16 controls for this driver. + */ +#define V4L2_CID_USER_NPCM_BASE (V4L2_CID_USER_BASE + 0x11b0) + /* MPEG-class control IDs */ /* The MPEG controls are applicable to all codec controls * and the 'MPEG' part of the define is historical */ From patchwork Wed Dec 14 09:26:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marvin Lin X-Patchwork-Id: 13072904 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 2BC23C4167B for ; Wed, 14 Dec 2022 09:28:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237912AbiLNJ2H (ORCPT ); Wed, 14 Dec 2022 04:28:07 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40994 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237781AbiLNJ1m (ORCPT ); Wed, 14 Dec 2022 04:27:42 -0500 Received: from mail-pf1-x42d.google.com (mail-pf1-x42d.google.com [IPv6:2607:f8b0:4864:20::42d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7B0EB26C1; Wed, 14 Dec 2022 01:27:40 -0800 (PST) Received: by mail-pf1-x42d.google.com with SMTP id n3so4010901pfq.10; Wed, 14 Dec 2022 01:27:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; 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=i3swy6qz7DvZvAluAP+tU7pAgPPOXXX+hPPdHMPIYTg=; b=TMY8qMQ41o0UKNmoR7w3ak/SW3CrXcIgoKdNfhVSPyrHEpCTX+r60lg+35CduOEPo0 EaxBu4Md+y1cyMv9cjROfOcs5JnNypGG8ehHXz2+xqx7HCWKY4ICC/JvxdNpaIehEonB YsVA6vdoUSBwo1n3hhIsvCdWlABUq3oHZtj3tGbOz1hp6vzps7910OslDNc0NAphoeT1 evvCNc4/3vh2czzmSR8DtCk3W2IP9yhbJ/j/h/Z1vIOvf3Q+JT8U15OSyCrIczUndYaO 43hVJlknTCritcgwiphKMsrZvP9jdnaF5kqd/o8k7171CoJ1Lho9NBC4vLGQLrXnaHgs D9ug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=i3swy6qz7DvZvAluAP+tU7pAgPPOXXX+hPPdHMPIYTg=; b=fhYypsyesWpUfokIgk2+KaiR8gJi9GyX6H7NiMwFujnAx8B0xdueDsCNCq4TXQrhIG 2gxXadXggx0YbXqE5TPXH1tEgijzxtENVFg268vG4JZ7FLbhOzy+D+ZbDT4wPLys6HV/ IePIZTYSmCpyYaRStmE7CwMJqEdj8b3QQLnoDvJo7hZypvgzH9Ibcv+OH4TAyXC1+QAt EtXd2OXRiHCKTGlFehonPviKPNKOE66TbOabIuSvez9/ismikWwz2CewK6HLvUS7koXU SWdCB8LO5gYr4E+pDXUK9DIntQL6NVN6rcB2M591C+OPsiR95+8qvORQiJ504TcWjV2z Dpwg== X-Gm-Message-State: ANoB5plxWvkufrIZOjablfDugvitbOgnFi4b4AHG4Guh8+VYhcBJbgzT ZOkuJ4FfE3ZS3KnmEkvo8tE= X-Google-Smtp-Source: AA0mqf7EMHk4eMG8aBuuEag5iuaURkFgS+i+28UGJuCIym7ihpwSHKMeYPvtUUW+G8yBURmjxx8DOQ== X-Received: by 2002:a05:6a00:26cc:b0:577:b52:4ec3 with SMTP id p12-20020a056a0026cc00b005770b524ec3mr21660543pfw.22.1671010059876; Wed, 14 Dec 2022 01:27:39 -0800 (PST) Received: from hcdev-d520mt2.. (60-250-192-107.hinet-ip.hinet.net. [60.250.192.107]) by smtp.gmail.com with ESMTPSA id t123-20020a628181000000b00576145a9bd0sm9003312pfd.127.2022.12.14.01.27.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 14 Dec 2022 01:27:39 -0800 (PST) From: Marvin Lin To: mchehab@kernel.org, linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org Cc: openbmc@lists.ozlabs.org, avifishman70@gmail.com, tmaimon77@gmail.com, tali.perry1@gmail.com, venture@google.com, yuenn@google.com, benjaminfair@google.com, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, kwliu@nuvoton.com, kflin@nuvoton.com, Marvin Lin Subject: [PATCH v8 6/7] media: uapi: Add controls for NPCM video driver Date: Wed, 14 Dec 2022 17:26:35 +0800 Message-Id: <20221214092636.810883-7-milkfafa@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20221214092636.810883-1-milkfafa@gmail.com> References: <20221214092636.810883-1-milkfafa@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Create controls for Nuvoton NPCM video driver to support setting capture mode of Video Capture/Differentiation (VCD) engine and getting the count of HEXTILE rectangles that is compressed by Encoding Compression Engine (ECE). Signed-off-by: Marvin Lin --- .../userspace-api/media/drivers/index.rst | 1 + .../media/drivers/npcm-video.rst | 67 +++++++++++++++++++ include/uapi/linux/npcm-video.h | 41 ++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 Documentation/userspace-api/media/drivers/npcm-video.rst create mode 100644 include/uapi/linux/npcm-video.h diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst index 915dbf0f4db5..97d2ce8da6b3 100644 --- a/Documentation/userspace-api/media/drivers/index.rst +++ b/Documentation/userspace-api/media/drivers/index.rst @@ -38,6 +38,7 @@ For more details see the file COPYING in the source distribution of Linux. imx-uapi max2175 meye-uapi + npcm-video omap3isp-uapi st-vgxy61 uvcvideo diff --git a/Documentation/userspace-api/media/drivers/npcm-video.rst b/Documentation/userspace-api/media/drivers/npcm-video.rst new file mode 100644 index 000000000000..abe9aac8fd34 --- /dev/null +++ b/Documentation/userspace-api/media/drivers/npcm-video.rst @@ -0,0 +1,67 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: + +NPCM video driver +================= + +This driver is used to control the Video Capture/Differentiation (VCD) engine +and Encoding Compression Engine (ECE) present on Nuvoton NPCM SoCs. The VCD can +capture and differentiate video data from digital or analog sources, then the +ECE will compress the data into HEXTILE format. + +Driver-specific Controls +------------------------ + +V4L2_CID_NPCM_CAPTURE_MODE +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The VCD engine supports two modes: + +- COMPLETE mode: + + Capture the next complete frame into memory. + +- DIFF mode: + + Compare the incoming frame with the frame stored in memory, and updates the + differentiated frame in memory. + +Application can use ``V4L2_CID_NPCM_CAPTURE_MODE`` control to set the VCD mode +with different control values (enum v4l2_npcm_capture_mode): + +- ``V4L2_NPCM_CAPTURE_MODE_COMPLETE``: will set VCD to COMPLETE mode. +- ``V4L2_NPCM_CAPTURE_MODE_DIFF``: will set VCD to DIFF mode. + +V4L2_CID_NPCM_RECT_COUNT +~~~~~~~~~~~~~~~~~~~~~~~~ + +After frame data is captured, the ECE will compress the data into HEXTILE format +and store these HEXTILE rectangles data in V4L2 video buffer with the layout +defined in Remote Framebuffer Protocol: +:: + + (RFC 6143, https://www.rfc-editor.org/rfc/rfc6143.html#section-7.6.1) + + +--------------+--------------+-------------------+ + | No. of bytes | Type [Value] | Description | + +--------------+--------------+-------------------+ + | 2 | U16 | x-position | + | 2 | U16 | y-position | + | 2 | U16 | width | + | 2 | U16 | height | + | 4 | S32 | encoding-type (5) | + +--------------+--------------+-------------------+ + | HEXTILE rectangle data | + +-------------------------------------------------+ + +Application can get these video buffers through V4L2 interfaces and use +``V4L2_CID_NPCM_RECT_COUNT`` control to get the count of compressed HEXTILE +rectangles that can be put in the field number-of-rectangles of +FramebufferUpdate header. + +References +---------- +include/uapi/linux/npcm-video.h + +**Copyright** |copy| 2022 Nuvoton Technologies diff --git a/include/uapi/linux/npcm-video.h b/include/uapi/linux/npcm-video.h new file mode 100644 index 000000000000..1d39f6f38c96 --- /dev/null +++ b/include/uapi/linux/npcm-video.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * Controls header for NPCM video driver + * + * Copyright (C) 2022 Nuvoton Technologies + */ + +#ifndef _UAPI_LINUX_NPCM_VIDEO_H +#define _UAPI_LINUX_NPCM_VIDEO_H + +#include + +/* + * Check Documentation/userspace-api/media/drivers/npcm-video.rst for control + * details. + */ + +/* + * This control is meant to set the mode of NPCM Video Capture/Differentiation + * (VCD) engine. + * + * The VCD engine supports two modes: + * COMPLETE - Capture the next complete frame into memory. + * DIFF - Compare the incoming frame with the frame stored in memory, and + * updates the differentiated frame in memory. + */ +#define V4L2_CID_NPCM_CAPTURE_MODE (V4L2_CID_USER_NPCM_BASE + 0) + +enum v4l2_npcm_capture_mode { + V4L2_NPCM_CAPTURE_MODE_COMPLETE = 0, /* COMPLETE mode */ + V4L2_NPCM_CAPTURE_MODE_DIFF = 1, /* DIFF mode */ +}; + +/* + * This control is meant to get the count of compressed HEXTILE rectangles which + * is relevant to the number of differentiated frames if VCD is in DIFF mode. + * And the count will always be 1 if VCD is in COMPLETE mode. + */ +#define V4L2_CID_NPCM_RECT_COUNT (V4L2_CID_USER_NPCM_BASE + 1) + +#endif /* _UAPI_LINUX_NPCM_VIDEO_H */ From patchwork Wed Dec 14 09:26:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Marvin Lin X-Patchwork-Id: 13072905 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 519FEC001B2 for ; Wed, 14 Dec 2022 09:28:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237943AbiLNJ2J (ORCPT ); Wed, 14 Dec 2022 04:28:09 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41042 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229757AbiLNJ1s (ORCPT ); Wed, 14 Dec 2022 04:27:48 -0500 Received: from mail-pg1-x532.google.com (mail-pg1-x532.google.com [IPv6:2607:f8b0:4864:20::532]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D7E695588; Wed, 14 Dec 2022 01:27:43 -0800 (PST) Received: by mail-pg1-x532.google.com with SMTP id 142so1592173pga.1; Wed, 14 Dec 2022 01:27:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; 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=rpFo+dhMfOYFKMtbjKVXPaWzXWY6Yl6XG8G3UeKK1OM=; b=I5kNdM4cBEvE816+r+6lUaFEGzbWccMzWxhsPW2T7Wkb/i632TVScnpO7KcyNQU2Eo QjO7PoWv1NmFCmwa0buWOu9XPXNDIfNNTzzBS9s27rdmmVK1caqe6ZqlPXv3kIQf7LhV bbLAvXtkweoabJ1uPyXMsyYm78HcHt9ZljNs3L+6CjaZnFfEFOggupGuhPj5mENQjO3U lJY0GsXirDzTXOBG7aRHRMdfdjGl/nxidqHjcWHFgLkJH059PS+iHNSfaKR8/KH4pnZF QZrq+rsiV4edZ24frjzgiB2PSq/i7rzF4B2vvYT8JuDnHFq/bR9ZYToqn5tKjPVDz7lN dJ6w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=rpFo+dhMfOYFKMtbjKVXPaWzXWY6Yl6XG8G3UeKK1OM=; b=xHbiAYDlFvkclgIuzbNR+2LpaGK8owFFV6tQDGJiZOhaDGLCgNbBcH2w06wJrglTXP qhxwO1P5PGGixNsAS6itvYDyvtynnAbnLXE83Rejn/Bl5oyYLCHbAMN0EfLr469uszHB zOcfrXBdPEU9isrPsekDLJBDTHaYrwjlZko8uNq/EH4sx/e7nXcZBXWBS+FKnwLPdrzp kSsG6RzNPbXXNktN6Pme1tbsnAPPIE0Lzinlq1fzOKhRtSFlL2xlJICSdzQFg36HDRRE aaCK0/RIq+XEvYXgHA5G2HeVA99MrnOXlQB15T18RFN6wl4bW6OdHdW9CX4aeIW5LaaE wTPg== X-Gm-Message-State: ANoB5pli85vRN3PFuh576BVAfDRNr5dbJoZscl0E4zTHiCDzo+id7hvp 3yE4nTxJkO/otsv7X9Y9bSE= X-Google-Smtp-Source: AA0mqf5x5Bk07zHB6Ap4WKr5vNPDiwWVIqBCVV9nDd1VAr5fdZURKPI0DSIU7ad1UNWD94AWB8WuUA== X-Received: by 2002:a05:6a00:278c:b0:578:3bc0:57d7 with SMTP id bd12-20020a056a00278c00b005783bc057d7mr13446996pfb.13.1671010062988; Wed, 14 Dec 2022 01:27:42 -0800 (PST) Received: from hcdev-d520mt2.. (60-250-192-107.hinet-ip.hinet.net. [60.250.192.107]) by smtp.gmail.com with ESMTPSA id t123-20020a628181000000b00576145a9bd0sm9003312pfd.127.2022.12.14.01.27.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 14 Dec 2022 01:27:42 -0800 (PST) From: Marvin Lin To: mchehab@kernel.org, linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org Cc: openbmc@lists.ozlabs.org, avifishman70@gmail.com, tmaimon77@gmail.com, tali.perry1@gmail.com, venture@google.com, yuenn@google.com, benjaminfair@google.com, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, kwliu@nuvoton.com, kflin@nuvoton.com, Marvin Lin Subject: [PATCH v8 7/7] media: nuvoton: Add driver for NPCM video capture and encode engine Date: Wed, 14 Dec 2022 17:26:36 +0800 Message-Id: <20221214092636.810883-8-milkfafa@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20221214092636.810883-1-milkfafa@gmail.com> References: <20221214092636.810883-1-milkfafa@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Add driver for Video Capture/Differentiation Engine (VCD) and Encoding Compression Engine (ECE) present on Nuvoton NPCM SoCs. The VCD can capture and differentiate video data from digital or analog sources, then the ECE will compress the data into HEXTILE format. This driver implements V4L2 interfaces and provides user controls to support KVM feature, also tested with VNC Viewer and openbmc/obmc-ikvm. Signed-off-by: Marvin Lin --- MAINTAINERS | 12 + drivers/media/platform/Kconfig | 1 + drivers/media/platform/Makefile | 1 + drivers/media/platform/nuvoton/Kconfig | 15 + drivers/media/platform/nuvoton/Makefile | 2 + drivers/media/platform/nuvoton/npcm-regs.h | 171 ++ drivers/media/platform/nuvoton/npcm-video.c | 1924 +++++++++++++++++++ 7 files changed, 2126 insertions(+) create mode 100644 drivers/media/platform/nuvoton/Kconfig create mode 100644 drivers/media/platform/nuvoton/Makefile create mode 100644 drivers/media/platform/nuvoton/npcm-regs.h create mode 100644 drivers/media/platform/nuvoton/npcm-video.c diff --git a/MAINTAINERS b/MAINTAINERS index 5a4526a171d6..d9f842ec141c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2570,6 +2570,18 @@ F: drivers/rtc/rtc-nct3018y.c F: include/dt-bindings/clock/nuvoton,npcm7xx-clock.h F: include/dt-bindings/clock/nuvoton,npcm845-clk.h +ARM/NUVOTON NPCM VIDEO ENGINE DRIVER +M: Joseph Liu +M: Marvin Lin +L: linux-media@vger.kernel.org +L: openbmc@lists.ozlabs.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/media/nuvoton,npcm-ece.yaml +F: Documentation/devicetree/bindings/media/nuvoton,npcm-vcd.yaml +F: Documentation/userspace-api/media/drivers/npcm-video.rst +F: drivers/media/platform/nuvoton/ +F: include/uapi/linux/npcm-video.h + ARM/NUVOTON WPCM450 ARCHITECTURE M: Jonathan Neuschäfer L: openbmc@lists.ozlabs.org (moderated for non-subscribers) diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index ee579916f874..91e54215de3a 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -73,6 +73,7 @@ source "drivers/media/platform/intel/Kconfig" source "drivers/media/platform/marvell/Kconfig" source "drivers/media/platform/mediatek/Kconfig" source "drivers/media/platform/microchip/Kconfig" +source "drivers/media/platform/nuvoton/Kconfig" source "drivers/media/platform/nvidia/Kconfig" source "drivers/media/platform/nxp/Kconfig" source "drivers/media/platform/qcom/Kconfig" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 5453bb868e67..3296ec1ebe16 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -16,6 +16,7 @@ obj-y += intel/ obj-y += marvell/ obj-y += mediatek/ obj-y += microchip/ +obj-y += nuvoton/ obj-y += nvidia/ obj-y += nxp/ obj-y += qcom/ diff --git a/drivers/media/platform/nuvoton/Kconfig b/drivers/media/platform/nuvoton/Kconfig new file mode 100644 index 000000000000..5047d1ba3de5 --- /dev/null +++ b/drivers/media/platform/nuvoton/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +comment "Nuvoton media platform drivers" + +config VIDEO_NPCM_VCD_ECE + tristate "Nuvoton NPCM Video Capture/Encode Engine driver" + depends on V4L_PLATFORM_DRIVERS + depends on VIDEO_DEV + select VIDEOBUF2_DMA_CONTIG + help + Support for the Video Capture/Differentiation Engine (VCD) and + Encoding Compression Engine (ECE) present on Nuvoton NPCM SoCs. + The VCD can capture and differentiate video data from digital or + analog sources, then the ECE will compress the data into HEXTILE + format. diff --git a/drivers/media/platform/nuvoton/Makefile b/drivers/media/platform/nuvoton/Makefile new file mode 100644 index 000000000000..74a4e3fc8555 --- /dev/null +++ b/drivers/media/platform/nuvoton/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_VIDEO_NPCM_VCD_ECE) += npcm-video.o diff --git a/drivers/media/platform/nuvoton/npcm-regs.h b/drivers/media/platform/nuvoton/npcm-regs.h new file mode 100644 index 000000000000..f528f5726307 --- /dev/null +++ b/drivers/media/platform/nuvoton/npcm-regs.h @@ -0,0 +1,171 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Register definition header for NPCM video driver + * + * Copyright (C) 2022 Nuvoton Technologies + */ + +#ifndef _NPCM_REGS_H +#define _NPCM_REGS_H + +/* VCD Registers */ +#define VCD_DIFF_TBL 0x0000 +#define VCD_FBA_ADR 0x8000 +#define VCD_FBB_ADR 0x8004 + +#define VCD_FB_LP 0x8008 +#define VCD_FBA_LP GENMASK(15, 0) +#define VCD_FBB_LP GENMASK(31, 16) + +#define VCD_CAP_RES 0x800c +#define VCD_CAP_RES_VERT_RES GENMASK(10, 0) +#define VCD_CAP_RES_HOR_RES GENMASK(26, 16) + +#define VCD_MODE 0x8014 +#define VCD_MODE_VCDE BIT(0) +#define VCD_MODE_CM565 BIT(1) +#define VCD_MODE_IDBC BIT(3) +#define VCD_MODE_COLOR_CNVRT GENMASK(5, 4) +#define VCD_MODE_COLOR_CNVRT_NO_CNVRT 0 +#define VCD_MODE_COLOR_CNVRT_RGB_222 1 +#define VCD_MODE_COLOR_CNVRT_666_MODE 2 +#define VCD_MODE_COLOR_CNVRT_RGB_888 3 +#define VCD_MODE_KVM_BW_SET BIT(16) + +#define VCD_CMD 0x8018 +#define VCD_CMD_GO BIT(0) +#define VCD_CMD_RST BIT(1) +#define VCD_CMD_OPERATION GENMASK(6, 4) +#define VCD_CMD_OPERATION_CAPTURE 0 +#define VCD_CMD_OPERATION_COMPARE 2 + +#define VCD_STAT 0x801c +#define VCD_STAT_DONE BIT(0) +#define VCD_STAT_IFOT BIT(2) +#define VCD_STAT_IFOR BIT(3) +#define VCD_STAT_BUSY BIT(30) +#define VCD_STAT_CLEAR 0x3fff + +#define VCD_INTE 0x8020 +#define VCD_INTE_DONE_IE BIT(0) +#define VCD_INTE_IFOT_IE BIT(2) +#define VCD_INTE_IFOR_IE BIT(3) + +#define VCD_RCHG 0x8028 +#define VCD_RCHG_TIM_PRSCL GENMASK(12, 9) + +#define VCD_FIFO 0x805c +#define VCD_FIFO_TH 0x100350ff + +#define VCD_MAX_SRC_BUFFER_SIZE 0x500000 /* 1920 x 1200 x 2 bpp */ +#define VCD_KVM_BW_PCLK 120000000UL +#define VCD_BUSY_TIMEOUT_US 300000 + +/* ECE Registers */ +#define ECE_DDA_CTRL 0x0000 +#define ECE_DDA_CTRL_ECEEN BIT(0) +#define ECE_DDA_CTRL_INTEN BIT(8) + +#define ECE_DDA_STS 0x0004 +#define ECE_DDA_STS_CDREADY BIT(8) +#define ECE_DDA_STS_ACDRDY BIT(10) + +#define ECE_FBR_BA 0x0008 +#define ECE_ED_BA 0x000c +#define ECE_RECT_XY 0x0010 + +#define ECE_RECT_DIMEN 0x0014 +#define ECE_RECT_DIMEN_WR GENMASK(10, 0) +#define ECE_RECT_DIMEN_WLTR GENMASK(14, 11) +#define ECE_RECT_DIMEN_HR GENMASK(26, 16) +#define ECE_RECT_DIMEN_HLTR GENMASK(30, 27) + +#define ECE_RESOL 0x001c +#define ECE_RESOL_FB_LP_512 0 +#define ECE_RESOL_FB_LP_1024 1 +#define ECE_RESOL_FB_LP_2048 2 +#define ECE_RESOL_FB_LP_2560 3 +#define ECE_RESOL_FB_LP_4096 4 + +#define ECE_HEX_CTRL 0x0040 +#define ECE_HEX_CTRL_ENCDIS BIT(0) +#define ECE_HEX_CTRL_ENC_GAP GENMASK(12, 8) + +#define ECE_HEX_RECT_OFFSET 0x0048 +#define ECE_HEX_RECT_OFFSET_MASK GENMASK(22, 0) + +#define ECE_TILE_W 16 +#define ECE_TILE_H 16 +#define ECE_POLL_TIMEOUT_US 300000 + +/* GCR Registers */ +#define INTCR 0x3c +#define INTCR_GFXIFDIS GENMASK(9, 8) +#define INTCR_DEHS BIT(27) + +#define INTCR2 0x60 +#define INTCR2_GIRST2 BIT(2) +#define INTCR2_GIHCRST BIT(5) +#define INTCR2_GIVCRST BIT(6) + +#define INTCR3 0x9c +#define INTCR3_GMMAP GENMASK(10, 8) +#define INTCR3_GMMAP_128MB 0 +#define INTCR3_GMMAP_256MB 1 +#define INTCR3_GMMAP_512MB 2 +#define INTCR3_GMMAP_1GB 3 +#define INTCR3_GMMAP_2GB 4 + +#define INTCR4 0xc0 +#define INTCR4_GMMAP GENMASK(22, 16) +#define INTCR4_GMMAP_512MB 0x1f +#define INTCR4_GMMAP_512MB_ECC 0x1b +#define INTCR4_GMMAP_1GB 0x3f +#define INTCR4_GMMAP_1GB_ECC 0x37 +#define INTCR4_GMMAP_2GB 0x7f +#define INTCR4_GMMAP_2GB_ECC 0x6f + +#define ADDR_GMMAP_128MB 0x07000000 +#define ADDR_GMMAP_256MB 0x0f000000 +#define ADDR_GMMAP_512MB 0x1f000000 +#define ADDR_GMMAP_512MB_ECC 0x1b000000 +#define ADDR_GMMAP_1GB 0x3f000000 +#define ADDR_GMMAP_1GB_ECC 0x37000000 +#define ADDR_GMMAP_2GB 0x7f000000 +#define ADDR_GMMAP_2GB_ECC 0x6f000000 + +#define GMMAP_LENGTH 0xc00000 /* 4MB preserved, total 16MB */ + +#define MFSEL1 0x0c +#define MFSEL1_DVH1SEL BIT(27) + +/* GFXI Register */ +#define DISPST 0x00 +#define DISPST_HSCROFF BIT(1) +#define DISPST_MGAMODE BIT(7) + +#define HVCNTL 0x10 +#define HVCNTL_MASK GENMASK(7, 0) + +#define HVCNTH 0x14 +#define HVCNTH_MASK GENMASK(2, 0) + +#define VVCNTL 0x20 +#define VVCNTL_MASK GENMASK(7, 0) + +#define VVCNTH 0x24 +#define VVCNTH_MASK GENMASK(2, 0) + +#define GPLLINDIV 0x40 +#define GPLLINDIV_MASK GENMASK(5, 0) +#define GPLLINDIV_GPLLFBDV8 BIT(7) + +#define GPLLFBDIV 0x44 +#define GPLLFBDIV_MASK GENMASK(7, 0) + +#define GPLLST 0x48 +#define GPLLST_PLLOTDIV1 GENMASK(2, 0) +#define GPLLST_PLLOTDIV2 GENMASK(5, 3) +#define GPLLST_GPLLFBDV109 GENMASK(7, 6) + +#endif /* _NPCM_REGS_H */ diff --git a/drivers/media/platform/nuvoton/npcm-video.c b/drivers/media/platform/nuvoton/npcm-video.c new file mode 100644 index 000000000000..951fdb4e37ca --- /dev/null +++ b/drivers/media/platform/nuvoton/npcm-video.c @@ -0,0 +1,1924 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Video Capture/Differentiation Engine (VCD) and Encoding + * Compression Engine (ECE) present on Nuvoton NPCM SoCs. + * + * Copyright (C) 2022 Nuvoton Technologies + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "npcm-regs.h" + +#define DEVICE_NAME "npcm-video" +#define MAX_FRAME_RATE 60 +#define MAX_WIDTH 1920 +#define MAX_HEIGHT 1200 +#define MIN_WIDTH 320 +#define MIN_HEIGHT 240 +#define MIN_LP 512 +#define MAX_LP 4096 +#define RECT_W 16 +#define RECT_H 16 +#define BITMAP_SIZE 32 + +struct npcm_video_addr { + size_t size; + dma_addr_t dma; + void *virt; +}; + +struct npcm_video_buffer { + struct vb2_v4l2_buffer vb; + struct list_head link; +}; + +#define to_npcm_video_buffer(x) \ + container_of((x), struct npcm_video_buffer, vb) + +enum { + VIDEO_STREAMING, + VIDEO_FRAME_INPRG, + VIDEO_STOPPED, +}; + +struct rect_list { + struct v4l2_clip clip; + struct list_head list; +}; + +struct rect_list_info { + struct rect_list *list; + struct rect_list *first; + struct list_head *head; + unsigned int index; + unsigned int tile_perline; + unsigned int tile_perrow; + unsigned int offset_perline; + unsigned int tile_size; + unsigned int tile_cnt; +}; + +struct npcm_ece { + struct regmap *regmap; + atomic_t clients; + struct reset_control *reset; +}; + +struct npcm_video { + struct regmap *gcr_regmap; + struct regmap *gfx_regmap; + struct regmap *vcd_regmap; + + struct device *dev; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_device v4l2_dev; + struct v4l2_pix_format pix_fmt; + struct v4l2_bt_timings active_timings; + struct v4l2_bt_timings detected_timings; + u32 v4l2_input_status; + struct vb2_queue queue; + struct video_device vdev; + struct mutex video_lock; /* v4l2 and videobuf2 lock */ + + struct list_head buffers; + spinlock_t lock; /* buffer list lock */ + unsigned long flags; + unsigned int sequence; + + size_t max_buffer_size; + struct npcm_video_addr src; + struct reset_control *reset; + struct npcm_ece ece; + + unsigned int frame_rate; + unsigned int vb_index; + u32 bytesperline; + u8 bytesperpixel; + u32 rect_cnt; + u8 num_buffers; + struct list_head *list; + u32 *rect; + int ctrl_cmd; + int op_cmd; +}; + +#define to_npcm_video(x) container_of((x), struct npcm_video, v4l2_dev) + +static const struct v4l2_dv_timings_cap npcm_video_timings_cap = { + .type = V4L2_DV_BT_656_1120, + .bt = { + .min_width = MIN_WIDTH, + .max_width = MAX_WIDTH, + .min_height = MIN_HEIGHT, + .max_height = MAX_HEIGHT, + .min_pixelclock = 6574080, /* 640 x 480 x 24Hz */ + .max_pixelclock = 138240000, /* 1920 x 1200 x 60Hz */ + .standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | + V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF, + .capabilities = V4L2_DV_BT_CAP_PROGRESSIVE | + V4L2_DV_BT_CAP_REDUCED_BLANKING | + V4L2_DV_BT_CAP_CUSTOM, + }, +}; + +static DECLARE_BITMAP(bitmap, BITMAP_SIZE); + +static void npcm_video_ece_prepend_rect_header(u8 *addr, u16 x, u16 y, u16 w, + u16 h) +{ + __be16 x_pos = cpu_to_be16(x); + __be16 y_pos = cpu_to_be16(y); + __be16 width = cpu_to_be16(w); + __be16 height = cpu_to_be16(h); + __be32 encoding = cpu_to_be32(5); /* Hextile encoding */ + + memcpy(addr, &x_pos, 2); + memcpy(addr + 2, &y_pos, 2); + memcpy(addr + 4, &width, 2); + memcpy(addr + 6, &height, 2); + memcpy(addr + 8, &encoding, 4); +} + +static unsigned int npcm_video_ece_get_ed_size(struct npcm_video *video, + u32 offset, u8 *addr) +{ + struct regmap *ece = video->ece.regmap; + u32 size, gap, val; + int ret; + + ret = regmap_read_poll_timeout(ece, ECE_DDA_STS, val, + (val & ECE_DDA_STS_CDREADY), + 0, ECE_POLL_TIMEOUT_US); + + if (ret) { + dev_warn(video->dev, "Wait for ECE_DDA_STS_CDREADY timeout\n"); + return 0; + } + + size = readl(addr + offset); + + regmap_read(ece, ECE_HEX_CTRL, &val); + gap = FIELD_GET(ECE_HEX_CTRL_ENC_GAP, val); + + dev_dbg(video->dev, "offset = %u, ed_size = %u, gap = %u\n", offset, + size, gap); + + return size + gap; +} + +static void npcm_video_ece_enc_rect(struct npcm_video *video, u32 r_off_x, + u32 r_off_y, u32 r_w, u32 r_h) +{ + struct regmap *ece = video->ece.regmap; + u32 rect_offset = (r_off_y * video->bytesperline) + (r_off_x * 2); + u32 temp; + u32 w_tile; + u32 h_tile; + u32 w_size = ECE_TILE_W; + u32 h_size = ECE_TILE_H; + + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_ECEEN, 0); + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_ECEEN, + ECE_DDA_CTRL_ECEEN); + regmap_write(ece, ECE_DDA_STS, ECE_DDA_STS_CDREADY | + ECE_DDA_STS_ACDRDY); + regmap_write(ece, ECE_RECT_XY, rect_offset); + + w_tile = r_w / ECE_TILE_W; + h_tile = r_h / ECE_TILE_H; + + if (r_w % ECE_TILE_W) { + w_tile += 1; + w_size = r_w % ECE_TILE_W; + } + + if (r_h % ECE_TILE_H || !h_tile) { + h_tile += 1; + h_size = r_h % ECE_TILE_H; + } + + temp = FIELD_PREP(ECE_RECT_DIMEN_WLTR, w_size - 1) | + FIELD_PREP(ECE_RECT_DIMEN_HLTR, h_size - 1) | + FIELD_PREP(ECE_RECT_DIMEN_WR, w_tile - 1) | + FIELD_PREP(ECE_RECT_DIMEN_HR, h_tile - 1); + + regmap_write(ece, ECE_RECT_DIMEN, temp); +} + +static u32 npcm_video_ece_read_rect_offset(struct npcm_video *video) +{ + struct regmap *ece = video->ece.regmap; + u32 offset; + + regmap_read(ece, ECE_HEX_RECT_OFFSET, &offset); + return FIELD_GET(ECE_HEX_RECT_OFFSET_MASK, offset); +} + +/* + * Set the line pitch (in bytes) for the frame buffers. + * Can be on of those values: 512, 1024, 2048, 2560 or 4096 bytes. + */ +static void npcm_video_ece_set_lp(struct npcm_video *video, u32 pitch) +{ + u32 lp; + struct regmap *ece = video->ece.regmap; + + switch (pitch) { + case 512: + lp = ECE_RESOL_FB_LP_512; + break; + case 1024: + lp = ECE_RESOL_FB_LP_1024; + break; + case 2048: + lp = ECE_RESOL_FB_LP_2048; + break; + case 2560: + lp = ECE_RESOL_FB_LP_2560; + break; + case 4096: + lp = ECE_RESOL_FB_LP_4096; + break; + default: + return; + } + + regmap_write(ece, ECE_RESOL, lp); +} + +static void npcm_video_ece_set_fb_addr(struct npcm_video *video, u32 buffer) +{ + struct regmap *ece = video->ece.regmap; + + regmap_write(ece, ECE_FBR_BA, buffer); +} + +static void npcm_video_ece_set_enc_dba(struct npcm_video *video, u32 addr) +{ + struct regmap *ece = video->ece.regmap; + + regmap_write(ece, ECE_ED_BA, addr); +} + +static void npcm_video_ece_clear_rect_offset(struct npcm_video *video) +{ + struct regmap *ece = video->ece.regmap; + + regmap_write(ece, ECE_HEX_RECT_OFFSET, 0); +} + +static void npcm_video_ece_ctrl_reset(struct npcm_video *video) +{ + struct regmap *ece = video->ece.regmap; + + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_ECEEN, 0); + regmap_update_bits(ece, ECE_HEX_CTRL, ECE_HEX_CTRL_ENCDIS, + ECE_HEX_CTRL_ENCDIS); + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_ECEEN, + ECE_DDA_CTRL_ECEEN); + regmap_update_bits(ece, ECE_HEX_CTRL, ECE_HEX_CTRL_ENCDIS, 0); + + npcm_video_ece_clear_rect_offset(video); +} + +static void npcm_video_ece_ip_reset(struct npcm_video *video) +{ + /* + * After resetting a module and clearing the reset bit, it should wait + * at least 10 us before accessing the module. + */ + reset_control_assert(video->ece.reset); + usleep_range(10, 20); + reset_control_deassert(video->ece.reset); + usleep_range(10, 20); +} + +static int npcm_video_ece_init(struct npcm_video *video) +{ + npcm_video_ece_ip_reset(video); + npcm_video_ece_ctrl_reset(video); + + return 0; +} + +static int npcm_video_ece_stop(struct npcm_video *video) +{ + struct regmap *ece = video->ece.regmap; + + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_ECEEN, 0); + regmap_update_bits(ece, ECE_DDA_CTRL, ECE_DDA_CTRL_INTEN, 0); + regmap_update_bits(ece, ECE_HEX_CTRL, ECE_HEX_CTRL_ENCDIS, + ECE_HEX_CTRL_ENCDIS); + npcm_video_ece_clear_rect_offset(video); + + return 0; +} + +static bool npcm_video_alloc_buf(struct npcm_video *video, + struct npcm_video_addr *addr, size_t size) +{ + if (size > VCD_MAX_SRC_BUFFER_SIZE) + size = VCD_MAX_SRC_BUFFER_SIZE; + + addr->virt = dma_alloc_coherent(video->dev, size, &addr->dma, + GFP_KERNEL); + + if (!addr->virt) + return false; + + addr->size = size; + return true; +} + +static void npcm_video_free_buf(struct npcm_video *video, + struct npcm_video_addr *addr) +{ + dma_free_coherent(video->dev, addr->size, addr->virt, addr->dma); + addr->size = 0; + addr->dma = 0ULL; + addr->virt = NULL; +} + +static void npcm_video_free_diff_table(struct npcm_video *video) +{ + struct list_head *head, *pos, *nx; + struct rect_list *tmp; + unsigned int i; + + for (i = 0; i < video->num_buffers; i++) { + head = &video->list[i]; + list_for_each_safe(pos, nx, head) { + tmp = list_entry(pos, struct rect_list, list); + list_del(&tmp->list); + kfree(tmp); + } + } +} + +static int npcm_video_add_rect(struct npcm_video *video, unsigned int index, + u32 x, u32 y, u32 w, u32 h) +{ + struct list_head *head = &video->list[index]; + struct rect_list *list = NULL; + struct v4l2_rect *r; + + list = kzalloc(sizeof(*list), GFP_KERNEL); + if (!list) + return 0; + + r = &list->clip.c; + r->left = x; + r->top = y; + r->width = w; + r->height = h; + + list_add_tail(&list->list, head); + return 1; +} + +static void npcm_video_merge_rect(struct npcm_video *video, + struct rect_list_info *info) +{ + struct list_head *head = info->head; + struct rect_list *list = info->list; + struct rect_list *first = info->first; + struct v4l2_rect *r = &list->clip.c; + struct v4l2_rect *f = &first->clip.c; + + if (!first) { + first = list; + info->first = first; + list_add_tail(&list->list, head); + video->rect_cnt++; + } else { + if ((r->left == (f->left + f->width)) && r->top == f->top) { + f->width += r->width; + kfree(list); + } else if ((r->top == (f->top + f->height)) && + (r->left == f->left)) { + f->height += r->height; + kfree(list); + } else if (((r->top > f->top) && + (r->top < (f->top + f->height))) && + ((r->left > f->left) && + (r->left < (f->left + f->width)))) { + kfree(list); + } else { + list_add_tail(&list->list, head); + video->rect_cnt++; + info->first = list; + } + } +} + +static struct rect_list *npcm_video_new_rect(struct npcm_video *video, + unsigned int offset, + unsigned int index) +{ + struct v4l2_bt_timings *act = &video->active_timings; + struct rect_list *list = NULL; + struct v4l2_rect *r; + + list = kzalloc(sizeof(*list), GFP_KERNEL); + if (!list) + return NULL; + + r = &list->clip.c; + + r->left = (offset << 4); + r->top = (index >> 2); + r->width = RECT_W; + r->height = RECT_H; + if ((r->left + RECT_W) > act->width) + r->width = act->width - r->left; + if ((r->top + RECT_H) > act->height) + r->height = act->height - r->top; + + return list; +} + +static int npcm_video_find_rect(struct npcm_video *video, + struct rect_list_info *info, + unsigned int offset) +{ + if (offset < info->tile_perline) { + info->list = npcm_video_new_rect(video, offset, info->index); + if (!info->list) + return -ENOMEM; + + npcm_video_merge_rect(video, info); + } + return 0; +} + +static int npcm_video_build_table(struct npcm_video *video, + struct rect_list_info *info) +{ + int ret; + unsigned int j, bit; + u32 value; + struct regmap *vcd = video->vcd_regmap; + + for (j = 0; j < info->offset_perline; j += 4) { + regmap_read(vcd, VCD_DIFF_TBL + (j + info->index), &value); + + bitmap_from_arr32(bitmap, &value, BITMAP_SIZE); + + for_each_set_bit(bit, bitmap, BITMAP_SIZE) { + ret = npcm_video_find_rect(video, info, bit + (j << 3)); + if (ret < 0) + return ret; + } + } + info->index += 64; + return info->tile_perline; +} + +static int npcm_video_get_rect_list(struct npcm_video *video, + unsigned int index) +{ + struct v4l2_bt_timings *act = &video->active_timings; + struct rect_list_info info; + int ret = 0; + unsigned int mod, tile_cnt = 0; + + memset(&info, 0, sizeof(struct rect_list_info)); + info.head = &video->list[index]; + + info.tile_perline = act->width >> 4; + mod = act->width % RECT_W; + if (mod != 0) + info.tile_perline += 1; + + info.tile_perrow = act->height >> 4; + mod = act->height % RECT_H; + if (mod != 0) + info.tile_perrow += 1; + + info.tile_size = info.tile_perrow * info.tile_perline; + + info.offset_perline = info.tile_perline >> 5; + mod = info.tile_perline % 32; + if (mod != 0) + info.offset_perline += 1; + + info.offset_perline *= 4; + + do { + ret = npcm_video_build_table(video, &info); + if (ret < 0) + return ret; + tile_cnt += ret; + } while (tile_cnt < info.tile_size); + + return ret; +} + +static unsigned int npcm_video_get_rect_count(struct npcm_video *video) +{ + struct list_head *head, *pos, *nx; + struct rect_list *tmp; + unsigned int count; + + if (video->list && video->rect) { + count = video->rect[video->vb_index]; + head = &video->list[video->vb_index]; + + list_for_each_safe(pos, nx, head) { + tmp = list_entry(pos, struct rect_list, list); + list_del(&tmp->list); + kfree(tmp); + } + } + + return count; +} + +static u8 npcm_video_is_mga(struct npcm_video *video) +{ + struct regmap *gfxi = video->gfx_regmap; + u32 dispst; + + regmap_read(gfxi, DISPST, &dispst); + return ((dispst & DISPST_MGAMODE) == DISPST_MGAMODE); +} + +static u32 npcm_video_hres(struct npcm_video *video) +{ + struct regmap *gfxi = video->gfx_regmap; + u32 hvcnth, hvcntl, apb_hor_res; + + regmap_read(gfxi, HVCNTH, &hvcnth); + regmap_read(gfxi, HVCNTL, &hvcntl); + apb_hor_res = (((hvcnth & HVCNTH_MASK) << 8) + + (hvcntl & HVCNTL_MASK) + 1); + + return apb_hor_res; +} + +static u32 npcm_video_vres(struct npcm_video *video) +{ + struct regmap *gfxi = video->gfx_regmap; + u32 vvcnth, vvcntl, apb_ver_res; + + regmap_read(gfxi, VVCNTH, &vvcnth); + regmap_read(gfxi, VVCNTL, &vvcntl); + + apb_ver_res = (((vvcnth & VVCNTH_MASK) << 8) + (vvcntl & VVCNTL_MASK)); + + return apb_ver_res; +} + +static int npcm_video_capres(struct npcm_video *video, u32 hor_res, + u32 vert_res) +{ + struct regmap *vcd = video->vcd_regmap; + u32 res, cap_res; + + if (hor_res > MAX_WIDTH || vert_res > MAX_HEIGHT) + return -EINVAL; + + res = FIELD_PREP(VCD_CAP_RES_VERT_RES, vert_res) | + FIELD_PREP(VCD_CAP_RES_HOR_RES, hor_res); + + regmap_write(vcd, VCD_CAP_RES, res); + regmap_read(vcd, VCD_CAP_RES, &cap_res); + + if (cap_res != res) + return -EINVAL; + + return 0; +} + +static void npcm_video_vcd_ip_reset(struct npcm_video *video) +{ + /* + * After resetting a module and clearing the reset bit, it should wait + * at least 10 us before accessing the module. + */ + reset_control_assert(video->reset); + usleep_range(10, 20); + reset_control_deassert(video->reset); + usleep_range(10, 20); +} + +static void npcm_video_vcd_state_machine_reset(struct npcm_video *video) +{ + struct regmap *vcd = video->vcd_regmap; + u32 stat; + int ret; + + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_VCDE, 0); + + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_IDBC, 0); + + regmap_update_bits(vcd, VCD_CMD, VCD_CMD_RST, VCD_CMD_RST); + + ret = regmap_read_poll_timeout(vcd, VCD_STAT, stat, + (stat & VCD_STAT_DONE), 0, + ECE_POLL_TIMEOUT_US); + + if (ret) { + dev_warn(video->dev, "Wait for VCD_STAT_DONE timeout\n"); + return; + } + + regmap_write(vcd, VCD_STAT, VCD_STAT_CLEAR); + + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_VCDE, VCD_MODE_VCDE); + + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_IDBC, VCD_MODE_IDBC); +} + +static int npcm_video_gfx_reset(struct npcm_video *video) +{ + struct regmap *gcr = video->gcr_regmap; + + regmap_update_bits(gcr, INTCR2, INTCR2_GIRST2, INTCR2_GIRST2); + + npcm_video_vcd_state_machine_reset(video); + + regmap_update_bits(gcr, INTCR2, INTCR2_GIRST2, 0); + + return 0; +} + +static void npcm_video_kvm_bw(struct npcm_video *video, u8 bandwidth) +{ + struct regmap *vcd = video->vcd_regmap; + + if (!npcm_video_is_mga(video)) + bandwidth = 1; + + if (bandwidth) + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_KVM_BW_SET, + VCD_MODE_KVM_BW_SET); + else + regmap_update_bits(vcd, VCD_MODE, VCD_MODE_KVM_BW_SET, 0); +} + +static u32 npcm_video_pclk(struct npcm_video *video) +{ + struct regmap *gfxi = video->gfx_regmap; + u32 tmp, pllfbdiv, pllinotdiv, gpllfbdiv; + u8 gpllfbdv109, gpllfbdv8, gpllindiv; + u8 gpllst_pllotdiv1, gpllst_pllotdiv2; + + regmap_read(gfxi, GPLLST, &tmp); + gpllfbdv109 = FIELD_GET(GPLLST_GPLLFBDV109, tmp); + gpllst_pllotdiv1 = FIELD_GET(GPLLST_PLLOTDIV1, tmp); + gpllst_pllotdiv2 = FIELD_GET(GPLLST_PLLOTDIV2, tmp); + + regmap_read(gfxi, GPLLINDIV, &tmp); + gpllfbdv8 = FIELD_GET(GPLLINDIV_GPLLFBDV8, tmp); + gpllindiv = FIELD_GET(GPLLINDIV_MASK, tmp); + + regmap_read(gfxi, GPLLFBDIV, &tmp); + gpllfbdiv = FIELD_GET(GPLLFBDIV_MASK, tmp); + + pllfbdiv = (512 * gpllfbdv109 + 256 * gpllfbdv8 + gpllfbdiv); + pllinotdiv = (gpllindiv * gpllst_pllotdiv1 * gpllst_pllotdiv2); + if (pllfbdiv == 0 || pllinotdiv == 0) + return 0; + + return ((pllfbdiv * 25000) / pllinotdiv) * 1000; +} + +static int npcm_video_get_bpp(struct npcm_video *video) +{ + struct regmap *vcd = video->vcd_regmap; + u32 mode, color_cnvr; + + regmap_read(vcd, VCD_MODE, &mode); + + color_cnvr = FIELD_GET(VCD_MODE_COLOR_CNVRT, mode); + + switch (color_cnvr) { + case VCD_MODE_COLOR_CNVRT_NO_CNVRT: + return 2; + case VCD_MODE_COLOR_CNVRT_RGB_222: + case VCD_MODE_COLOR_CNVRT_666_MODE: + return 1; + case VCD_MODE_COLOR_CNVRT_RGB_888: + return 4; + } + return 0; +} + +/* + * Pitch must be a power of 2, >= linebytes, + * at least 512, and no more than 4096. + */ +static void npcm_video_set_linepitch(struct npcm_video *video, u32 linebytes) +{ + struct regmap *vcd = video->vcd_regmap; + u32 pitch = MIN_LP; + + while ((pitch < linebytes) && (pitch < MAX_LP)) + pitch *= 2; + + regmap_write(vcd, VCD_FB_LP, FIELD_PREP(VCD_FBA_LP, pitch) | + FIELD_PREP(VCD_FBB_LP, pitch)); +} + +static u32 npcm_video_get_linepitch(struct npcm_video *video) +{ + struct regmap *vcd = video->vcd_regmap; + u32 linepitch; + + regmap_read(vcd, VCD_FB_LP, &linepitch); + + return FIELD_GET(VCD_FBA_LP, linepitch); +} + +static int npcm_video_command(struct npcm_video *video, u32 value) +{ + struct regmap *vcd = video->vcd_regmap; + u32 cmd; + + regmap_write(vcd, VCD_STAT, VCD_STAT_CLEAR); + + regmap_read(vcd, VCD_CMD, &cmd); + cmd |= FIELD_PREP(VCD_CMD_OPERATION, value); + + regmap_write(vcd, VCD_CMD, cmd); + regmap_update_bits(vcd, VCD_CMD, VCD_CMD_GO, VCD_CMD_GO); + video->op_cmd = value; + + return 0; +} + +static int npcm_video_init_reg(struct npcm_video *video) +{ + struct regmap *gcr = video->gcr_regmap; + struct regmap *vcd = video->vcd_regmap; + + /* Selects Data Enable */ + regmap_update_bits(gcr, INTCR, INTCR_DEHS, 0); + + /* Enable display of KVM GFX and access to memory */ + regmap_update_bits(gcr, INTCR, INTCR_GFXIFDIS, 0); + + /* Active Vertical/Horizontal Counters Reset */ + regmap_update_bits(gcr, INTCR2, INTCR2_GIHCRST | INTCR2_GIVCRST, + INTCR2_GIHCRST | INTCR2_GIVCRST); + + /* Select KVM GFX input */ + regmap_update_bits(gcr, MFSEL1, MFSEL1_DVH1SEL, 0); + + /* Reset video modules */ + npcm_video_vcd_ip_reset(video); + npcm_video_gfx_reset(video); + + /* Set the FIFO thresholds */ + regmap_write(vcd, VCD_FIFO, VCD_FIFO_TH); + + /* Set video mode */ + regmap_update_bits(vcd, VCD_MODE, 0xffffffff, + VCD_MODE_VCDE | VCD_MODE_CM565 | + VCD_MODE_IDBC | VCD_MODE_KVM_BW_SET); + + regmap_write(vcd, VCD_RCHG, FIELD_PREP(VCD_RCHG_TIM_PRSCL, 0xf)); + + return 0; +} + +static int npcm_video_start_frame(struct npcm_video *video) +{ + unsigned long flags; + struct npcm_video_buffer *buf; + struct regmap *vcd = video->vcd_regmap; + u32 val; + int ret; + + if (video->v4l2_input_status) { + dev_dbg(video->dev, "No video signal; skip capture frame\n"); + return 0; + } + + ret = regmap_read_poll_timeout(vcd, VCD_STAT, val, + !(val & VCD_STAT_BUSY), 1000, + VCD_BUSY_TIMEOUT_US); + + if (ret) { + dev_err(video->dev, "Wait for VCD_STAT_BUSY timeout\n"); + return -EBUSY; + } + + spin_lock_irqsave(&video->lock, flags); + buf = list_first_entry_or_null(&video->buffers, + struct npcm_video_buffer, link); + if (!buf) { + spin_unlock_irqrestore(&video->lock, flags); + dev_dbg(video->dev, "No empty buffers; skip capture frame\n"); + return 0; + } + + set_bit(VIDEO_FRAME_INPRG, &video->flags); + spin_unlock_irqrestore(&video->lock, flags); + + npcm_video_vcd_state_machine_reset(video); + + regmap_update_bits(vcd, VCD_INTE, VCD_INTE_DONE_IE | VCD_INTE_IFOT_IE | + VCD_INTE_IFOR_IE, VCD_INTE_DONE_IE | + VCD_INTE_IFOT_IE | VCD_INTE_IFOR_IE); + + npcm_video_command(video, video->ctrl_cmd); + + return 0; +} + +static void npcm_video_bufs_done(struct npcm_video *video, + enum vb2_buffer_state state) +{ + unsigned long flags; + struct npcm_video_buffer *buf; + + spin_lock_irqsave(&video->lock, flags); + list_for_each_entry(buf, &video->buffers, link) + vb2_buffer_done(&buf->vb.vb2_buf, state); + INIT_LIST_HEAD(&video->buffers); + spin_unlock_irqrestore(&video->lock, flags); +} + +static void npcm_video_get_diff_rect(struct npcm_video *video, + unsigned int index) +{ + u32 width = video->active_timings.width; + u32 height = video->active_timings.height; + + if (video->op_cmd != VCD_CMD_OPERATION_CAPTURE) { + video->rect_cnt = 0; + npcm_video_get_rect_list(video, index); + video->rect[index] = video->rect_cnt; + } else { + video->rect[index] = npcm_video_add_rect(video, index, 0, 0, + width, height); + } +} + +static irqreturn_t npcm_video_irq(int irq, void *arg) +{ + struct npcm_video *video = arg; + struct regmap *vcd = video->vcd_regmap; + struct npcm_video_buffer *buf; + struct rect_list *rect_list; + struct v4l2_rect *rect; + u32 status, ed_offset; + void *addr; + dma_addr_t vb_dma_addr; + unsigned int index, ed_size, total_size; + + regmap_read(vcd, VCD_STAT, &status); + dev_dbg(video->dev, "VCD irq status 0x%x\n", status); + + regmap_write(vcd, VCD_INTE, 0); + regmap_write(vcd, VCD_STAT, VCD_STAT_CLEAR); + + if (test_bit(VIDEO_STOPPED, &video->flags) || + !test_bit(VIDEO_STREAMING, &video->flags)) { + clear_bit(VIDEO_FRAME_INPRG, &video->flags); + return IRQ_NONE; + } + + if (status & VCD_STAT_DONE) { + spin_lock(&video->lock); + buf = list_first_entry_or_null(&video->buffers, + struct npcm_video_buffer, + link); + + if (!buf) { + spin_unlock(&video->lock); + clear_bit(VIDEO_FRAME_INPRG, &video->flags); + return IRQ_NONE; + } + + addr = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + vb_dma_addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, + 0); + index = buf->vb.vb2_buf.index; + + npcm_video_ece_ctrl_reset(video); + npcm_video_ece_clear_rect_offset(video); + + npcm_video_ece_set_fb_addr(video, video->src.dma); + + /* Set base address of encoded data to video buffer */ + npcm_video_ece_set_enc_dba(video, vb_dma_addr); + + npcm_video_ece_set_lp(video, video->bytesperline); + npcm_video_get_diff_rect(video, index); + + total_size = 0; + + list_for_each_entry(rect_list, &video->list[index], list) { + rect = &rect_list->clip.c; + ed_offset = npcm_video_ece_read_rect_offset(video); + + npcm_video_ece_enc_rect(video, rect->left, + rect->top, rect->width, + rect->height); + ed_size = npcm_video_ece_get_ed_size(video, + ed_offset, + addr); + + npcm_video_ece_prepend_rect_header(addr + ed_offset, + rect->left, + rect->top, + rect->width, + rect->height); + + total_size += ed_size; + } + + vb2_set_plane_payload(&buf->vb.vb2_buf, 0, total_size); + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + buf->vb.sequence = video->sequence++; + buf->vb.field = V4L2_FIELD_NONE; + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + list_del(&buf->link); + + spin_unlock(&video->lock); + + clear_bit(VIDEO_FRAME_INPRG, &video->flags); + } + + if (status & VCD_STAT_IFOR || status & VCD_STAT_IFOT) { + dev_warn(video->dev, "VCD FIFO overrun or over thresholds\n"); + npcm_video_vcd_ip_reset(video); + npcm_video_gfx_reset(video); + npcm_video_start_frame(video); + } + + return IRQ_HANDLED; +} + +static void npcm_video_clear_gmmap(struct npcm_video *video) +{ + struct regmap *gcr = video->gcr_regmap; + u32 intcr, gmmap; + void __iomem *baseptr; + + if (of_device_is_compatible(video->dev->of_node, + "nuvoton,npcm750-vcd")) { + regmap_read(gcr, INTCR3, &intcr); + gmmap = FIELD_GET(INTCR3_GMMAP, intcr); + + switch (gmmap) { + case INTCR3_GMMAP_128MB: + baseptr = ioremap_wc(ADDR_GMMAP_128MB, GMMAP_LENGTH); + break; + case INTCR3_GMMAP_256MB: + baseptr = ioremap_wc(ADDR_GMMAP_256MB, GMMAP_LENGTH); + break; + case INTCR3_GMMAP_512MB: + baseptr = ioremap_wc(ADDR_GMMAP_512MB, GMMAP_LENGTH); + break; + case INTCR3_GMMAP_1GB: + baseptr = ioremap_wc(ADDR_GMMAP_1GB, GMMAP_LENGTH); + break; + case INTCR3_GMMAP_2GB: + baseptr = ioremap_wc(ADDR_GMMAP_2GB, GMMAP_LENGTH); + break; + } + } else if (of_device_is_compatible(video->dev->of_node, + "nuvoton,npcm845-vcd")) { + regmap_read(gcr, INTCR4, &intcr); + gmmap = FIELD_GET(INTCR4_GMMAP, intcr); + + switch (gmmap) { + case INTCR4_GMMAP_512MB: + baseptr = ioremap_wc(ADDR_GMMAP_512MB, GMMAP_LENGTH); + break; + case INTCR4_GMMAP_512MB_ECC: + baseptr = ioremap_wc(ADDR_GMMAP_512MB_ECC, + GMMAP_LENGTH); + break; + case INTCR4_GMMAP_1GB: + baseptr = ioremap_wc(ADDR_GMMAP_1GB, GMMAP_LENGTH); + break; + case INTCR4_GMMAP_1GB_ECC: + baseptr = ioremap_wc(ADDR_GMMAP_1GB_ECC, GMMAP_LENGTH); + break; + case INTCR4_GMMAP_2GB: + baseptr = ioremap_wc(ADDR_GMMAP_2GB, GMMAP_LENGTH); + break; + case INTCR4_GMMAP_2GB_ECC: + baseptr = ioremap_wc(ADDR_GMMAP_2GB_ECC, GMMAP_LENGTH); + break; + } + } + + memset(baseptr, 0, GMMAP_LENGTH); + iounmap(baseptr); +} + +static void npcm_video_get_resolution(struct npcm_video *video) +{ + struct v4l2_bt_timings *act = &video->active_timings; + struct v4l2_bt_timings *det = &video->detected_timings; + struct regmap *gfxi; + u32 dispst; + + video->v4l2_input_status = 0; + + det->width = npcm_video_hres(video); + det->height = npcm_video_vres(video); + + if (act->width != det->width || act->height != det->height) { + dev_dbg(video->dev, "Resolution changed\n"); + + npcm_video_bufs_done(video, VB2_BUF_STATE_ERROR); + + if (npcm_video_hres(video) > 0 && npcm_video_vres(video) > 0) { + gfxi = video->gfx_regmap; + + if (test_bit(VIDEO_STREAMING, &video->flags)) { + /* + * Wait for resolution is available, + * and it is also captured by host. + */ + do { + mdelay(100); + regmap_read(gfxi, DISPST, &dispst); + } while (npcm_video_vres(video) < 100 || + npcm_video_pclk(video) == 0 || + (dispst & DISPST_HSCROFF)); + } + + det->width = npcm_video_hres(video); + det->height = npcm_video_vres(video); + det->pixelclock = npcm_video_pclk(video); + } + } + + if (det->width == 0 || det->height == 0) { + det->width = MIN_WIDTH; + det->height = MIN_HEIGHT; + npcm_video_clear_gmmap(video); + video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; + } + + dev_dbg(video->dev, "Got resolution[%dx%d] -> [%dx%d], status %d\n", + act->width, act->height, det->width, det->height, + video->v4l2_input_status); +} + +static void npcm_video_set_resolution(struct npcm_video *video) +{ + struct v4l2_bt_timings *act = &video->active_timings; + struct regmap *vcd = video->vcd_regmap; + u32 mode; + + /* Set video frame physical address */ + regmap_write(vcd, VCD_FBA_ADR, video->src.dma); + regmap_write(vcd, VCD_FBB_ADR, video->src.dma); + + npcm_video_capres(video, act->width, act->height); + + video->bytesperpixel = npcm_video_get_bpp(video); + npcm_video_set_linepitch(video, act->width * video->bytesperpixel); + + video->bytesperline = npcm_video_get_linepitch(video); + + npcm_video_kvm_bw(video, act->pixelclock > VCD_KVM_BW_PCLK); + + npcm_video_gfx_reset(video); + + regmap_read(vcd, VCD_MODE, &mode); + + clear_bit(VIDEO_FRAME_INPRG, &video->flags); + + dev_dbg(video->dev, "VCD mode = 0x%x, %s mode\n", mode, + npcm_video_is_mga(video) ? "Hi Res" : "VGA"); + + dev_dbg(video->dev, + "Digital mode: %d x %d x %d, pixelclock %lld, bytesperline %d\n", + act->width, act->height, video->bytesperpixel, act->pixelclock, + video->bytesperline); +} + +static int npcm_video_start(struct npcm_video *video) +{ + int rc; + + rc = npcm_video_init_reg(video); + if (rc) + return rc; + + npcm_video_get_resolution(video); + + video->active_timings = video->detected_timings; + + video->max_buffer_size = VCD_MAX_SRC_BUFFER_SIZE; + if (!npcm_video_alloc_buf(video, &video->src, video->max_buffer_size)) + return -ENOMEM; + + npcm_video_set_resolution(video); + + video->pix_fmt.width = video->active_timings.width; + video->pix_fmt.height = video->active_timings.height; + video->pix_fmt.sizeimage = video->max_buffer_size; + video->pix_fmt.bytesperline = video->bytesperline; + + if (atomic_inc_return(&video->ece.clients) == 1) { + npcm_video_ece_init(video); + npcm_video_ece_set_fb_addr(video, video->src.dma); + npcm_video_ece_set_lp(video, video->bytesperline); + + dev_dbg(video->dev, "ECE open: client %d\n", + atomic_read(&video->ece.clients)); + } + + return 0; +} + +static void npcm_video_stop(struct npcm_video *video) +{ + unsigned long flags; + struct regmap *vcd = video->vcd_regmap; + + spin_lock_irqsave(&video->lock, flags); + set_bit(VIDEO_STOPPED, &video->flags); + spin_unlock_irqrestore(&video->lock, flags); + + regmap_write(vcd, VCD_INTE, 0); + regmap_write(vcd, VCD_MODE, 0); + regmap_write(vcd, VCD_RCHG, 0); + regmap_write(vcd, VCD_STAT, VCD_STAT_CLEAR); + + if (video->src.size) + npcm_video_free_buf(video, &video->src); + + if (video->list) + npcm_video_free_diff_table(video); + + kfree(video->list); + video->list = NULL; + + kfree(video->rect); + video->rect = NULL; + + video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; + video->flags = 0; + video->ctrl_cmd = VCD_CMD_OPERATION_CAPTURE; + + if (atomic_dec_return(&video->ece.clients) == 0) { + npcm_video_ece_stop(video); + dev_dbg(video->dev, "ECE close: client %d\n", + atomic_read(&video->ece.clients)); + } +} + +static int npcm_video_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, DEVICE_NAME, sizeof(cap->driver)); + strscpy(cap->card, "NPCM Video Engine", sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + DEVICE_NAME); + + return 0; +} + +static int npcm_video_enum_format(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + if (f->index) + return -EINVAL; + + f->pixelformat = V4L2_PIX_FMT_HEXTILE; + + return 0; +} + +static int npcm_video_get_format(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct npcm_video *video = video_drvdata(file); + + f->fmt.pix = video->pix_fmt; + + return 0; +} + +static int npcm_video_enum_input(struct file *file, void *fh, + struct v4l2_input *inp) +{ + struct npcm_video *video = video_drvdata(file); + + if (inp->index) + return -EINVAL; + + strscpy(inp->name, "Host VGA capture", sizeof(inp->name)); + inp->type = V4L2_INPUT_TYPE_CAMERA; + inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; + inp->status = video->v4l2_input_status; + + return 0; +} + +static int npcm_video_get_input(struct file *file, void *fh, unsigned int *i) +{ + *i = 0; + + return 0; +} + +static int npcm_video_set_input(struct file *file, void *fh, unsigned int i) +{ + if (i) + return -EINVAL; + + return 0; +} + +static int npcm_video_get_parm(struct file *file, void *fh, + struct v4l2_streamparm *a) +{ + struct npcm_video *video = video_drvdata(file); + + a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + a->parm.capture.readbuffers = 3; + a->parm.capture.timeperframe.numerator = 1; + if (!video->frame_rate) + a->parm.capture.timeperframe.denominator = MAX_FRAME_RATE; + else + a->parm.capture.timeperframe.denominator = video->frame_rate; + + return 0; +} + +static int npcm_video_set_parm(struct file *file, void *fh, + struct v4l2_streamparm *a) +{ + unsigned int frame_rate = 0; + + a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + a->parm.capture.readbuffers = 3; + + if (a->parm.capture.timeperframe.numerator) + frame_rate = a->parm.capture.timeperframe.denominator / + a->parm.capture.timeperframe.numerator; + + if (!frame_rate || frame_rate > MAX_FRAME_RATE) { + frame_rate = 0; + a->parm.capture.timeperframe.denominator = MAX_FRAME_RATE; + a->parm.capture.timeperframe.numerator = 1; + } + + return 0; +} + +static int npcm_video_set_dv_timings(struct file *file, void *fh, + struct v4l2_dv_timings *timings) +{ + struct npcm_video *video = video_drvdata(file); + + if (timings->bt.width == video->active_timings.width && + timings->bt.height == video->active_timings.height) + return 0; + + if (vb2_is_busy(&video->queue)) { + dev_err(video->dev, "%s device busy\n", __func__); + return -EBUSY; + } + + video->active_timings = timings->bt; + + npcm_video_set_resolution(video); + + video->pix_fmt.width = timings->bt.width; + video->pix_fmt.height = timings->bt.height; + video->pix_fmt.sizeimage = video->max_buffer_size; + video->pix_fmt.bytesperline = video->bytesperline; + + timings->type = V4L2_DV_BT_656_1120; + + return 0; +} + +static int npcm_video_get_dv_timings(struct file *file, void *fh, + struct v4l2_dv_timings *timings) +{ + struct npcm_video *video = video_drvdata(file); + + timings->type = V4L2_DV_BT_656_1120; + timings->bt = video->active_timings; + + return 0; +} + +static int npcm_video_query_dv_timings(struct file *file, void *fh, + struct v4l2_dv_timings *timings) +{ + struct npcm_video *video = video_drvdata(file); + + npcm_video_get_resolution(video); + + timings->type = V4L2_DV_BT_656_1120; + timings->bt = video->detected_timings; + + return video->v4l2_input_status ? -ENOLINK : 0; +} + +static int npcm_video_enum_dv_timings(struct file *file, void *fh, + struct v4l2_enum_dv_timings *timings) +{ + return v4l2_enum_dv_timings_cap(timings, &npcm_video_timings_cap, + NULL, NULL); +} + +static int npcm_video_dv_timings_cap(struct file *file, void *fh, + struct v4l2_dv_timings_cap *cap) +{ + *cap = npcm_video_timings_cap; + + return 0; +} + +static int npcm_video_sub_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subscribe(fh, sub); + } + + return v4l2_ctrl_subscribe_event(fh, sub); +} + +static const struct v4l2_ioctl_ops npcm_video_ioctls = { + .vidioc_querycap = npcm_video_querycap, + + .vidioc_enum_fmt_vid_cap = npcm_video_enum_format, + .vidioc_g_fmt_vid_cap = npcm_video_get_format, + .vidioc_s_fmt_vid_cap = npcm_video_get_format, + .vidioc_try_fmt_vid_cap = npcm_video_get_format, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .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, + + .vidioc_enum_input = npcm_video_enum_input, + .vidioc_g_input = npcm_video_get_input, + .vidioc_s_input = npcm_video_set_input, + + .vidioc_g_parm = npcm_video_get_parm, + .vidioc_s_parm = npcm_video_set_parm, + + .vidioc_s_dv_timings = npcm_video_set_dv_timings, + .vidioc_g_dv_timings = npcm_video_get_dv_timings, + .vidioc_query_dv_timings = npcm_video_query_dv_timings, + .vidioc_enum_dv_timings = npcm_video_enum_dv_timings, + .vidioc_dv_timings_cap = npcm_video_dv_timings_cap, + + .vidioc_subscribe_event = npcm_video_sub_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int npcm_video_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct npcm_video *video = container_of(ctrl->handler, + struct npcm_video, + ctrl_handler); + + switch (ctrl->id) { + case V4L2_CID_NPCM_CAPTURE_MODE: + if (ctrl->val == V4L2_NPCM_CAPTURE_MODE_COMPLETE) + video->ctrl_cmd = VCD_CMD_OPERATION_CAPTURE; + else if (ctrl->val == V4L2_NPCM_CAPTURE_MODE_DIFF) + video->ctrl_cmd = VCD_CMD_OPERATION_COMPARE; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int npcm_video_get_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct npcm_video *video = container_of(ctrl->handler, + struct npcm_video, + ctrl_handler); + + switch (ctrl->id) { + case V4L2_CID_NPCM_RECT_COUNT: + ctrl->val = npcm_video_get_rect_count(video); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops npcm_video_ctrl_ops = { + .s_ctrl = npcm_video_set_ctrl, + .g_volatile_ctrl = npcm_video_get_volatile_ctrl, +}; + +static const struct v4l2_ctrl_config npcm_ctrl_capture_mode = { + .ops = &npcm_video_ctrl_ops, + .id = V4L2_CID_NPCM_CAPTURE_MODE, + .name = "NPCM Video Capture Mode", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = V4L2_NPCM_CAPTURE_MODE_DIFF, + .step = 1, + .def = 0, +}; + +static const struct v4l2_ctrl_config npcm_ctrl_rect_count = { + .ops = &npcm_video_ctrl_ops, + .id = V4L2_CID_NPCM_RECT_COUNT, + .name = "NPCM Compressed Hextile Rectangle Count", + .type = V4L2_CTRL_TYPE_INTEGER, + .flags = V4L2_CTRL_FLAG_VOLATILE, + .min = 0, + .max = (MAX_WIDTH / RECT_W) * (MAX_HEIGHT / RECT_H), + .step = 1, + .def = 0, +}; + +static int npcm_video_open(struct file *file) +{ + int rc; + struct npcm_video *video = video_drvdata(file); + + mutex_lock(&video->video_lock); + + rc = v4l2_fh_open(file); + if (rc) { + mutex_unlock(&video->video_lock); + return rc; + } + + if (v4l2_fh_is_singular_file(file)) + npcm_video_start(video); + + mutex_unlock(&video->video_lock); + + return 0; +} + +static int npcm_video_release(struct file *file) +{ + int rc; + struct npcm_video *video = video_drvdata(file); + + mutex_lock(&video->video_lock); + + if (v4l2_fh_is_singular_file(file)) + npcm_video_stop(video); + + rc = _vb2_fop_release(file, NULL); + + mutex_unlock(&video->video_lock); + + return rc; +} + +static const struct v4l2_file_operations npcm_video_v4l2_fops = { + .owner = THIS_MODULE, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, + .open = npcm_video_open, + .release = npcm_video_release, +}; + +static int npcm_video_queue_setup(struct vb2_queue *q, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct npcm_video *video = vb2_get_drv_priv(q); + unsigned int i; + + if (*num_planes) { + if (sizes[0] < video->max_buffer_size) + return -EINVAL; + + return 0; + } + + *num_planes = 1; + sizes[0] = video->max_buffer_size; + + kfree(video->rect); + video->rect = NULL; + + video->rect = kcalloc(*num_buffers, sizeof(*video->rect), GFP_KERNEL); + if (!video->rect) + return -ENOMEM; + + if (video->list) { + npcm_video_free_diff_table(video); + kfree(video->list); + video->list = NULL; + } + + video->list = kzalloc(sizeof(*video->list) * *num_buffers, GFP_KERNEL); + if (!video->list) { + kfree(video->rect); + return -ENOMEM; + } + + for (i = 0; i < *num_buffers; i++) + INIT_LIST_HEAD(&video->list[i]); + + video->num_buffers = *num_buffers; + + return 0; +} + +static int npcm_video_buf_prepare(struct vb2_buffer *vb) +{ + struct npcm_video *video = vb2_get_drv_priv(vb->vb2_queue); + + if (vb2_plane_size(vb, 0) < video->max_buffer_size) + return -EINVAL; + + return 0; +} + +static int npcm_video_start_streaming(struct vb2_queue *q, unsigned int count) +{ + int rc; + struct npcm_video *video = vb2_get_drv_priv(q); + + video->sequence = 0; + + rc = npcm_video_start_frame(video); + if (rc) { + npcm_video_bufs_done(video, VB2_BUF_STATE_QUEUED); + return rc; + } + + set_bit(VIDEO_STREAMING, &video->flags); + return 0; +} + +static void npcm_video_stop_streaming(struct vb2_queue *q) +{ + struct npcm_video *video = vb2_get_drv_priv(q); + struct regmap *vcd = video->vcd_regmap; + + clear_bit(VIDEO_STREAMING, &video->flags); + + regmap_write(vcd, VCD_INTE, 0); + regmap_write(vcd, VCD_STAT, VCD_STAT_CLEAR); + npcm_video_gfx_reset(video); + + npcm_video_bufs_done(video, VB2_BUF_STATE_ERROR); + + video->ctrl_cmd = VCD_CMD_OPERATION_CAPTURE; +} + +static void npcm_video_buf_queue(struct vb2_buffer *vb) +{ + struct npcm_video *video = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct npcm_video_buffer *nvb = to_npcm_video_buffer(vbuf); + unsigned long flags; + + spin_lock_irqsave(&video->lock, flags); + list_add_tail(&nvb->link, &video->buffers); + spin_unlock_irqrestore(&video->lock, flags); +} + +static void npcm_video_buf_finish(struct vb2_buffer *vb) +{ + struct npcm_video *video = vb2_get_drv_priv(vb->vb2_queue); + struct regmap *vcd = video->vcd_regmap; + u32 val; + int ret; + + ret = regmap_read_poll_timeout(vcd, VCD_STAT, val, + !(val & VCD_STAT_BUSY), 1000, + VCD_BUSY_TIMEOUT_US); + + if (ret) { + dev_warn(video->dev, "Wait for VCD_STAT_BUSY timeout\n"); + return; + } + + /* Capture next frame when a video buffer is dequeued */ + npcm_video_start_frame(video); + + video->vb_index = vb->index; +} + +static const struct vb2_ops npcm_video_vb2_ops = { + .queue_setup = npcm_video_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_prepare = npcm_video_buf_prepare, + .buf_finish = npcm_video_buf_finish, + .start_streaming = npcm_video_start_streaming, + .stop_streaming = npcm_video_stop_streaming, + .buf_queue = npcm_video_buf_queue, +}; + +static int npcm_video_setup_video(struct npcm_video *video) +{ + struct v4l2_device *v4l2_dev = &video->v4l2_dev; + struct video_device *vdev = &video->vdev; + struct vb2_queue *vbq = &video->queue; + int rc; + + video->pix_fmt.pixelformat = V4L2_PIX_FMT_HEXTILE; + video->pix_fmt.field = V4L2_FIELD_NONE; + video->pix_fmt.colorspace = V4L2_COLORSPACE_SRGB; + video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; + + rc = v4l2_device_register(video->dev, v4l2_dev); + if (rc) { + dev_err(video->dev, "Failed to register v4l2 device\n"); + return rc; + } + + v4l2_ctrl_handler_init(&video->ctrl_handler, 2); + v4l2_ctrl_new_custom(&video->ctrl_handler, &npcm_ctrl_capture_mode, + NULL); + v4l2_ctrl_new_custom(&video->ctrl_handler, &npcm_ctrl_rect_count, NULL); + + if (video->ctrl_handler.error) { + dev_err(video->dev, "Failed to init controls: %d\n", + video->ctrl_handler.error); + + rc = video->ctrl_handler.error; + goto rel_ctrl_handler; + } + + v4l2_dev->ctrl_handler = &video->ctrl_handler; + + vbq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vbq->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; + vbq->dev = v4l2_dev->dev; + vbq->lock = &video->video_lock; + vbq->ops = &npcm_video_vb2_ops; + vbq->mem_ops = &vb2_dma_contig_memops; + vbq->drv_priv = video; + vbq->buf_struct_size = sizeof(struct npcm_video_buffer); + vbq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vbq->min_buffers_needed = 3; + + rc = vb2_queue_init(vbq); + if (rc) { + dev_err(video->dev, "Failed to init vb2 queue\n"); + goto rel_ctrl_handler; + } + + vdev->queue = vbq; + vdev->fops = &npcm_video_v4l2_fops; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + vdev->v4l2_dev = v4l2_dev; + strscpy(vdev->name, DEVICE_NAME, sizeof(vdev->name)); + vdev->vfl_type = VFL_TYPE_VIDEO; + vdev->vfl_dir = VFL_DIR_RX; + vdev->release = video_device_release_empty; + vdev->ioctl_ops = &npcm_video_ioctls; + vdev->lock = &video->video_lock; + + video_set_drvdata(vdev, video); + rc = video_register_device(vdev, VFL_TYPE_VIDEO, 0); + if (rc) { + dev_err(video->dev, "Failed to register video device\n"); + goto rel_vb_queue; + } + + return 0; + +rel_vb_queue: + vb2_queue_release(vbq); +rel_ctrl_handler: + v4l2_ctrl_handler_free(&video->ctrl_handler); + v4l2_device_unregister(v4l2_dev); + + return rc; +} + +static int npcm_video_init(struct npcm_video *video) +{ + int irq; + int rc; + struct device *dev = video->dev; + + irq = irq_of_parse_and_map(dev->of_node, 0); + if (!irq) { + dev_err(dev, "Failed to find VCD IRQ\n"); + return -ENODEV; + } + + rc = devm_request_threaded_irq(dev, irq, NULL, npcm_video_irq, + IRQF_ONESHOT, DEVICE_NAME, video); + if (rc < 0) { + dev_err(dev, "Failed to request IRQ %d\n", irq); + return rc; + } + + of_reserved_mem_device_init(dev); + + rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (rc) { + dev_err(dev, "Failed to set DMA mask\n"); + of_reserved_mem_device_release(dev); + } + + return rc; +} + +static const struct regmap_config npcm_video_regmap_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = VCD_FIFO, +}; + +static const struct regmap_config npcm_video_ece_regmap_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = ECE_HEX_RECT_OFFSET, +}; + +static int npcm_video_probe(struct platform_device *pdev) +{ + int rc; + void __iomem *regs; + struct npcm_video *video = kzalloc(sizeof(*video), GFP_KERNEL); + struct device_node *ece_node; + struct platform_device *ece_pdev; + + if (!video) + return -ENOMEM; + + video->frame_rate = MAX_FRAME_RATE; + video->dev = &pdev->dev; + spin_lock_init(&video->lock); + mutex_init(&video->video_lock); + INIT_LIST_HEAD(&video->buffers); + + regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regs)) { + dev_err(&pdev->dev, "Failed to parse VCD reg in DTS\n"); + return PTR_ERR(regs); + } + + video->vcd_regmap = devm_regmap_init_mmio(&pdev->dev, regs, + &npcm_video_regmap_cfg); + if (IS_ERR(video->vcd_regmap)) { + dev_err(&pdev->dev, "Failed to initialize VCD regmap\n"); + return PTR_ERR(video->vcd_regmap); + } + + ece_node = of_parse_phandle(video->dev->of_node, "nuvoton,ece", 0); + if (IS_ERR(ece_node)) { + dev_err(&pdev->dev, "Failed to get ECE phandle in DTS\n"); + return PTR_ERR(ece_node); + } + + ece_pdev = of_find_device_by_node(ece_node); + of_node_put(ece_node); + if (IS_ERR(ece_pdev)) { + dev_err(&pdev->dev, "Failed to find ECE device\n"); + return PTR_ERR(ece_pdev); + } + + regs = devm_platform_ioremap_resource(ece_pdev, 0); + if (IS_ERR(regs)) { + dev_err(&pdev->dev, "Failed to parse ECE reg in DTS\n"); + return PTR_ERR(regs); + } + + video->ece.regmap = devm_regmap_init_mmio(&pdev->dev, regs, + &npcm_video_ece_regmap_cfg); + if (IS_ERR(video->ece.regmap)) { + dev_err(&pdev->dev, "Failed to initialize ECE regmap\n"); + return PTR_ERR(video->ece.regmap); + } + + video->reset = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(video->reset)) { + dev_err(&pdev->dev, "Failed to get VCD reset control in DTS\n"); + return PTR_ERR(video->reset); + } + + video->ece.reset = devm_reset_control_get(&ece_pdev->dev, NULL); + if (IS_ERR(video->ece.reset)) { + dev_err(&pdev->dev, "Failed to get ECE reset control in DTS\n"); + return PTR_ERR(video->ece.reset); + } + + video->gcr_regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "nuvoton,sysgcr"); + if (IS_ERR(video->gcr_regmap)) + return PTR_ERR(video->gcr_regmap); + + video->gfx_regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "nuvoton,sysgfxi"); + if (IS_ERR(video->gfx_regmap)) + return PTR_ERR(video->gfx_regmap); + + rc = npcm_video_init(video); + if (rc) + return rc; + + rc = npcm_video_setup_video(video); + if (rc) + return rc; + + dev_info(video->dev, "NPCM video driver probed\n"); + + return 0; +} + +static int npcm_video_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); + struct npcm_video *video = to_npcm_video(v4l2_dev); + + video_unregister_device(&video->vdev); + + vb2_queue_release(&video->queue); + + v4l2_ctrl_handler_free(&video->ctrl_handler); + + v4l2_device_unregister(v4l2_dev); + + npcm_video_ece_stop(video); + + of_reserved_mem_device_release(dev); + + return 0; +} + +static const struct of_device_id npcm_video_match[] = { + { .compatible = "nuvoton,npcm750-vcd" }, + { .compatible = "nuvoton,npcm845-vcd" }, + {}, +}; + +MODULE_DEVICE_TABLE(of, npcm_video_match); + +static struct platform_driver npcm_video_driver = { + .driver = { + .name = DEVICE_NAME, + .of_match_table = npcm_video_match, + }, + .probe = npcm_video_probe, + .remove = npcm_video_remove, +}; + +module_platform_driver(npcm_video_driver); + +MODULE_AUTHOR("Joseph Liu"); +MODULE_AUTHOR("Marvin Lin"); +MODULE_DESCRIPTION("Driver for Nuvoton NPCM Video Capture/Encode Engine"); +MODULE_LICENSE("GPL");