Hi all,
with the release of documentation headers for Tegra multimedia engines (NVDEC, NVENC, NVJPG) [1], I have started working on the corresponding implementations. Here's the first one, NVDEC.
The kernel driver is a simple Falcon boot driver based on the VIC driver. Some code sharing should be considered there in the future. The userspace driver to accompany this is a bit more complicated - I have expanded vaapi-tegra-driver[2] to support MPEG2 decoding. It should be noted that the implementation is still very clunky and has poor performance, but it's a start.
This series is based on top of the "Host1x/TegraDRM UAPI" series. For testing, appropriate firmware should be obtained from a Linux for Tegra distribution for now; the GPU should also be enabled in the device tree.
Series was tested on Tegra186.
Thanks!
Mikko
[1] https://github.com/NVIDIA/open-gpu-doc/tree/master/classes/video [2] https://github.com/cyndis/vaapi-tegra-driver
Mikko Perttunen (3): dt-bindings: Add YAML bindings for Host1x and NVDEC arm64: tegra: Add NVDEC to Tegra186 device tree drm/tegra: Add NVDEC driver
.../gpu/host1x/nvidia,tegra20-host1x.yaml | 129 +++++ .../gpu/host1x/nvidia,tegra210-nvdec.yaml | 90 ++++ MAINTAINERS | 1 + arch/arm64/boot/dts/nvidia/tegra186.dtsi | 15 + drivers/gpu/drm/tegra/Makefile | 3 +- drivers/gpu/drm/tegra/drm.c | 4 + drivers/gpu/drm/tegra/drm.h | 1 + drivers/gpu/drm/tegra/nvdec.c | 497 ++++++++++++++++++ drivers/gpu/host1x/dev.c | 12 + include/linux/host1x.h | 1 + 10 files changed, 752 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml create mode 100644 Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml create mode 100644 drivers/gpu/drm/tegra/nvdec.c
Convert the original Host1x bindings to YAML and add new bindings for NVDEC, now in a more appropriate location. The old text bindings for Host1x and engines are still kept at display/tegra/ since they encompass a lot more engines that haven't been converted over yet.
Signed-off-by: Mikko Perttunen mperttunen@nvidia.com --- .../gpu/host1x/nvidia,tegra20-host1x.yaml | 129 ++++++++++++++++++ .../gpu/host1x/nvidia,tegra210-nvdec.yaml | 90 ++++++++++++ MAINTAINERS | 1 + 3 files changed, 220 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml create mode 100644 Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml
diff --git a/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml new file mode 100644 index 000000000000..613c6601f0f1 --- /dev/null +++ b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml @@ -0,0 +1,129 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/gpu/host1x/nvidia,tegra20-host1x.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Device tree binding for NVIDIA Host1x + +maintainers: + - Thierry Reding treding@gmail.com + - Mikko Perttunen mperttunen@nvidia.com + +properties: + $nodename: + pattern: "^host1x@[0-9a-f]*$" + + compatible: + oneOf: + - const: nvidia,tegra20-host1x + - const: nvidia,tegra30-host1x + - const: nvidia,tegra114-host1x + - const: nvidia,tegra124-host1x + - items: + - const: nvidia,tegra132-host1x + - const: nvidia,tegra124-host1x + - const: nvidia,tegra210-host1x + + reg: + maxItems: 1 + + interrupts: + items: + - description: Syncpoint threshold interrupt + - description: General interrupt + + interrupt-names: + items: + - const: syncpt + - const: host1x + + clocks: + maxItems: 1 + + clock-names: + items: + - const: host1x + + resets: + maxItems: 1 + + reset-names: + items: + - const: host1x + + iommus: + maxItems: 1 + + interconnects: + maxItems: 1 + + interconnect-names: + items: + - const: dma-mem + + '#address-cells': + const: 1 + + '#size-cells': + const: 1 + + ranges: true + +required: + - compatible + - reg + - interrupts + - interrupt-names + - clocks + - clock-names + - resets + - reset-names + - '#address-cells' + - '#size-cells' + - ranges + +additionalProperties: + type: object + +if: + properties: + compatible: + contains: + anyOf: + - const: nvidia,tegra186-host1x + - const: nvidia,tegra194-host1x +then: + properties: + reg: + items: + - description: Hypervisor-accessible register area + - description: VM-accessible register area + reg-names: + items: + - const: hypervisor + - const: vm + required: + - reg-names + +examples: + - | + #include <dt-bindings/clock/tegra20-car.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + host1x@50000000 { + compatible = "nvidia,tegra20-host1x"; + reg = <0x50000000 0x00024000>; + interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>, /* syncpt */ + <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; /* general */ + interrupt-names = "syncpt", "host1x"; + clocks = <&tegra_car TEGRA20_CLK_HOST1X>; + clock-names = "host1x"; + resets = <&tegra_car 28>; + reset-names = "host1x"; + + #address-cells = <1>; + #size-cells = <1>; + + ranges = <0x54000000 0x54000000 0x04000000>; + }; diff --git a/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml new file mode 100644 index 000000000000..9a6334d930c8 --- /dev/null +++ b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/gpu/host1x/nvidia,tegra210-nvdec.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Device tree binding for NVIDIA Tegra VIC + +maintainers: + - Thierry Reding treding@gmail.com + - Mikko Perttunen mperttunen@nvidia.com + +properties: + $nodename: + pattern: "^nvdec@[0-9a-f]*$" + + compatible: + enum: + - nvidia,tegra210-nvdec + - nvidia,tegra186-nvdec + - nvidia,tegra194-nvdec + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: nvdec + + resets: + maxItems: 1 + + reset-names: + items: + - const: nvdec + + power-domains: + maxItems: 1 + + iommus: + maxItems: 1 + + interconnects: + items: + - description: DMA read memory client + - description: DMA write memory client + + interconnect-names: + items: + - const: dma-mem + - const: write + +required: + - compatible + - reg + - clocks + - clock-names + - resets + - reset-names + - power-domains + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/tegra186-clock.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/memory/tegra186-mc.h> + #include <dt-bindings/power/tegra186-powergate.h> + #include <dt-bindings/reset/tegra186-reset.h> + + nvdec@15480000 { + compatible = "nvidia,tegra186-nvdec"; + reg = <0x15480000 0x40000>; + clocks = <&bpmp TEGRA186_CLK_NVDEC>; + clock-names = "nvdec"; + resets = <&bpmp TEGRA186_RESET_NVDEC>; + reset-names = "nvdec"; + + power-domains = <&bpmp TEGRA186_POWER_DOMAIN_NVDEC>; + interconnects = <&mc TEGRA186_MEMORY_CLIENT_NVDECSRD &emc>, + <&mc TEGRA186_MEMORY_CLIENT_NVDECSWR &emc>; + interconnect-names = "dma-mem", "write"; + iommus = <&smmu TEGRA186_SID_NVDEC>; + }; + + diff --git a/MAINTAINERS b/MAINTAINERS index 8170b40d6236..b892419c6564 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5950,6 +5950,7 @@ L: linux-tegra@vger.kernel.org S: Supported T: git git://anongit.freedesktop.org/tegra/linux.git F: Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt +F: Documentation/devicetree/bindings/gpu/host1x/ F: drivers/gpu/drm/tegra/ F: drivers/gpu/host1x/ F: include/linux/host1x.h
On 13/02/2021 11:15, Mikko Perttunen wrote:
Convert the original Host1x bindings to YAML and add new bindings for NVDEC, now in a more appropriate location. The old text bindings for Host1x and engines are still kept at display/tegra/ since they encompass a lot more engines that haven't been converted over yet.
Signed-off-by: Mikko Perttunen mperttunen@nvidia.com
.../gpu/host1x/nvidia,tegra20-host1x.yaml | 129 ++++++++++++++++++ .../gpu/host1x/nvidia,tegra210-nvdec.yaml | 90 ++++++++++++ MAINTAINERS | 1 + 3 files changed, 220 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml create mode 100644 Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml
diff --git a/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml new file mode 100644 index 000000000000..613c6601f0f1 --- /dev/null +++ b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml @@ -0,0 +1,129 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/gpu/host1x/nvidia,tegra20-host1x.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+title: Device tree binding for NVIDIA Host1x
+maintainers:
- Thierry Reding treding@gmail.com
- Mikko Perttunen mperttunen@nvidia.com
+properties:
- $nodename:
- pattern: "^host1x@[0-9a-f]*$"
- compatible:
- oneOf:
- const: nvidia,tegra20-host1x
- const: nvidia,tegra30-host1x
- const: nvidia,tegra114-host1x
- const: nvidia,tegra124-host1x
- items:
- const: nvidia,tegra132-host1x
- const: nvidia,tegra124-host1x
- const: nvidia,tegra210-host1x
- reg:
- maxItems: 1
- interrupts:
- items:
- description: Syncpoint threshold interrupt
- description: General interrupt
- interrupt-names:
- items:
- const: syncpt
- const: host1x
- clocks:
- maxItems: 1
- clock-names:
- items:
- const: host1x
- resets:
- maxItems: 1
- reset-names:
- items:
- const: host1x
- iommus:
- maxItems: 1
- interconnects:
- maxItems: 1
- interconnect-names:
- items:
- const: dma-mem
- '#address-cells':
- const: 1
- '#size-cells':
- const: 1
- ranges: true
+required:
- compatible
- reg
- interrupts
- interrupt-names
- clocks
- clock-names
- resets
- reset-names
- '#address-cells'
- '#size-cells'
- ranges
+additionalProperties:
- type: object
+if:
- properties:
- compatible:
contains:
anyOf:
- const: nvidia,tegra186-host1x
- const: nvidia,tegra194-host1x
+then:
- properties:
- reg:
items:
- description: Hypervisor-accessible register area
- description: VM-accessible register area
- reg-names:
items:
- const: hypervisor
- const: vm
- required:
- reg-names
+examples:
- |
- #include <dt-bindings/clock/tegra20-car.h>
- #include <dt-bindings/interrupt-controller/arm-gic.h>
- host1x@50000000 {
compatible = "nvidia,tegra20-host1x";
reg = <0x50000000 0x00024000>;
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>, /* syncpt */
<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; /* general */
interrupt-names = "syncpt", "host1x";
clocks = <&tegra_car TEGRA20_CLK_HOST1X>;
clock-names = "host1x";
resets = <&tegra_car 28>;
reset-names = "host1x";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x54000000 0x54000000 0x04000000>;
- };
diff --git a/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml new file mode 100644 index 000000000000..9a6334d930c8 --- /dev/null +++ b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/gpu/host1x/nvidia,tegra210-nvdec.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+title: Device tree binding for NVIDIA Tegra VIC
-----------------------------------------------/\ Should be NVDEC ?
Neil
+maintainers:
- Thierry Reding treding@gmail.com
- Mikko Perttunen mperttunen@nvidia.com
+properties:
- $nodename:
- pattern: "^nvdec@[0-9a-f]*$"
- compatible:
- enum:
- nvidia,tegra210-nvdec
- nvidia,tegra186-nvdec
- nvidia,tegra194-nvdec
- reg:
- maxItems: 1
- clocks:
- maxItems: 1
- clock-names:
- items:
- const: nvdec
- resets:
- maxItems: 1
- reset-names:
- items:
- const: nvdec
- power-domains:
- maxItems: 1
- iommus:
- maxItems: 1
- interconnects:
- items:
- description: DMA read memory client
- description: DMA write memory client
- interconnect-names:
- items:
- const: dma-mem
- const: write
+required:
- compatible
- reg
- clocks
- clock-names
- resets
- reset-names
- power-domains
+additionalProperties: false
+examples:
- |
- #include <dt-bindings/clock/tegra186-clock.h>
- #include <dt-bindings/interrupt-controller/arm-gic.h>
- #include <dt-bindings/memory/tegra186-mc.h>
- #include <dt-bindings/power/tegra186-powergate.h>
- #include <dt-bindings/reset/tegra186-reset.h>
- nvdec@15480000 {
compatible = "nvidia,tegra186-nvdec";
reg = <0x15480000 0x40000>;
clocks = <&bpmp TEGRA186_CLK_NVDEC>;
clock-names = "nvdec";
resets = <&bpmp TEGRA186_RESET_NVDEC>;
reset-names = "nvdec";
power-domains = <&bpmp TEGRA186_POWER_DOMAIN_NVDEC>;
interconnects = <&mc TEGRA186_MEMORY_CLIENT_NVDECSRD &emc>,
<&mc TEGRA186_MEMORY_CLIENT_NVDECSWR &emc>;
interconnect-names = "dma-mem", "write";
iommus = <&smmu TEGRA186_SID_NVDEC>;
- };
diff --git a/MAINTAINERS b/MAINTAINERS index 8170b40d6236..b892419c6564 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5950,6 +5950,7 @@ L: linux-tegra@vger.kernel.org S: Supported T: git git://anongit.freedesktop.org/tegra/linux.git F: Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt +F: Documentation/devicetree/bindings/gpu/host1x/ F: drivers/gpu/drm/tegra/ F: drivers/gpu/host1x/ F: include/linux/host1x.h
On Sat, 13 Feb 2021 12:15:10 +0200, Mikko Perttunen wrote:
Convert the original Host1x bindings to YAML and add new bindings for NVDEC, now in a more appropriate location. The old text bindings for Host1x and engines are still kept at display/tegra/ since they encompass a lot more engines that haven't been converted over yet.
Signed-off-by: Mikko Perttunen mperttunen@nvidia.com
.../gpu/host1x/nvidia,tegra20-host1x.yaml | 129 ++++++++++++++++++ .../gpu/host1x/nvidia,tegra210-nvdec.yaml | 90 ++++++++++++ MAINTAINERS | 1 + 3 files changed, 220 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml create mode 100644 Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors: ./Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml:90:1: [warning] too many blank lines (2 > 1) (empty-lines)
dtschema/dtc warnings/errors:
See https://patchwork.ozlabs.org/patch/1440164
This check can fail if there are any dependencies. The base for a patch series is generally the most recent rc1.
If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date:
pip3 install dtschema --upgrade
Please check and re-submit.
On Sat, Feb 13, 2021 at 12:15:10PM +0200, Mikko Perttunen wrote:
Convert the original Host1x bindings to YAML and add new bindings for NVDEC, now in a more appropriate location. The old text bindings for Host1x and engines are still kept at display/tegra/ since they encompass a lot more engines that haven't been converted over yet.
Signed-off-by: Mikko Perttunen mperttunen@nvidia.com
.../gpu/host1x/nvidia,tegra20-host1x.yaml | 129 ++++++++++++++++++ .../gpu/host1x/nvidia,tegra210-nvdec.yaml | 90 ++++++++++++ MAINTAINERS | 1 + 3 files changed, 220 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml create mode 100644 Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml
diff --git a/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml new file mode 100644 index 000000000000..613c6601f0f1 --- /dev/null +++ b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml @@ -0,0 +1,129 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/gpu/host1x/nvidia,tegra20-host1x.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+title: Device tree binding for NVIDIA Host1x
+maintainers:
- Thierry Reding treding@gmail.com
- Mikko Perttunen mperttunen@nvidia.com
+properties:
- $nodename:
- pattern: "^host1x@[0-9a-f]*$"
- compatible:
- oneOf:
- const: nvidia,tegra20-host1x
- const: nvidia,tegra30-host1x
- const: nvidia,tegra114-host1x
- const: nvidia,tegra124-host1x
- items:
- const: nvidia,tegra132-host1x
- const: nvidia,tegra124-host1x
- const: nvidia,tegra210-host1x
- reg:
- maxItems: 1
- interrupts:
- items:
- description: Syncpoint threshold interrupt
- description: General interrupt
- interrupt-names:
- items:
- const: syncpt
- const: host1x
- clocks:
- maxItems: 1
- clock-names:
- items:
- const: host1x
- resets:
- maxItems: 1
- reset-names:
- items:
- const: host1x
- iommus:
- maxItems: 1
- interconnects:
- maxItems: 1
- interconnect-names:
- items:
- const: dma-mem
- '#address-cells':
- const: 1
- '#size-cells':
- const: 1
- ranges: true
+required:
- compatible
- reg
- interrupts
- interrupt-names
- clocks
- clock-names
- resets
- reset-names
- '#address-cells'
- '#size-cells'
- ranges
+additionalProperties:
- type: object
+if:
- properties:
- compatible:
contains:
anyOf:
- const: nvidia,tegra186-host1x
- const: nvidia,tegra194-host1x
Just use 'enum' instead of 'anyOf' and 'const'.
+then:
- properties:
- reg:
items:
- description: Hypervisor-accessible register area
- description: VM-accessible register area
If you test this, it will fail due to the 'maxItems: 1' above. The main section has to pass for all conditions and then if/them schema add constraints.
- reg-names:
items:
- const: hypervisor
- const: vm
- required:
- reg-names
+examples:
- |
- #include <dt-bindings/clock/tegra20-car.h>
- #include <dt-bindings/interrupt-controller/arm-gic.h>
- host1x@50000000 {
compatible = "nvidia,tegra20-host1x";
reg = <0x50000000 0x00024000>;
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>, /* syncpt */
<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; /* general */
interrupt-names = "syncpt", "host1x";
clocks = <&tegra_car TEGRA20_CLK_HOST1X>;
clock-names = "host1x";
resets = <&tegra_car 28>;
reset-names = "host1x";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x54000000 0x54000000 0x04000000>;
- };
diff --git a/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml new file mode 100644 index 000000000000..9a6334d930c8 --- /dev/null +++ b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/gpu/host1x/nvidia,tegra210-nvdec.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+title: Device tree binding for NVIDIA Tegra VIC
I'm left wondering what NVDEC and VIC are?
+maintainers:
- Thierry Reding treding@gmail.com
- Mikko Perttunen mperttunen@nvidia.com
+properties:
- $nodename:
- pattern: "^nvdec@[0-9a-f]*$"
- compatible:
- enum:
- nvidia,tegra210-nvdec
- nvidia,tegra186-nvdec
- nvidia,tegra194-nvdec
- reg:
- maxItems: 1
- clocks:
- maxItems: 1
- clock-names:
- items:
- const: nvdec
- resets:
- maxItems: 1
- reset-names:
- items:
- const: nvdec
- power-domains:
- maxItems: 1
- iommus:
- maxItems: 1
- interconnects:
- items:
- description: DMA read memory client
- description: DMA write memory client
- interconnect-names:
- items:
- const: dma-mem
- const: write
+required:
- compatible
- reg
- clocks
- clock-names
- resets
- reset-names
- power-domains
+additionalProperties: false
+examples:
- |
- #include <dt-bindings/clock/tegra186-clock.h>
- #include <dt-bindings/interrupt-controller/arm-gic.h>
- #include <dt-bindings/memory/tegra186-mc.h>
- #include <dt-bindings/power/tegra186-powergate.h>
- #include <dt-bindings/reset/tegra186-reset.h>
- nvdec@15480000 {
compatible = "nvidia,tegra186-nvdec";
reg = <0x15480000 0x40000>;
clocks = <&bpmp TEGRA186_CLK_NVDEC>;
clock-names = "nvdec";
resets = <&bpmp TEGRA186_RESET_NVDEC>;
reset-names = "nvdec";
power-domains = <&bpmp TEGRA186_POWER_DOMAIN_NVDEC>;
interconnects = <&mc TEGRA186_MEMORY_CLIENT_NVDECSRD &emc>,
<&mc TEGRA186_MEMORY_CLIENT_NVDECSWR &emc>;
interconnect-names = "dma-mem", "write";
iommus = <&smmu TEGRA186_SID_NVDEC>;
- };
diff --git a/MAINTAINERS b/MAINTAINERS index 8170b40d6236..b892419c6564 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5950,6 +5950,7 @@ L: linux-tegra@vger.kernel.org S: Supported T: git git://anongit.freedesktop.org/tegra/linux.git F: Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt +F: Documentation/devicetree/bindings/gpu/host1x/ F: drivers/gpu/drm/tegra/ F: drivers/gpu/host1x/ F: include/linux/host1x.h -- 2.30.0
On 2/17/21 11:49 PM, Rob Herring wrote:
On Sat, Feb 13, 2021 at 12:15:10PM +0200, Mikko Perttunen wrote:
Convert the original Host1x bindings to YAML and add new bindings for NVDEC, now in a more appropriate location. The old text bindings for Host1x and engines are still kept at display/tegra/ since they encompass a lot more engines that haven't been converted over yet.
Signed-off-by: Mikko Perttunen mperttunen@nvidia.com
.../gpu/host1x/nvidia,tegra20-host1x.yaml | 129 ++++++++++++++++++ .../gpu/host1x/nvidia,tegra210-nvdec.yaml | 90 ++++++++++++ MAINTAINERS | 1 + 3 files changed, 220 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml create mode 100644 Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml
diff --git a/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml new file mode 100644 index 000000000000..613c6601f0f1 --- /dev/null +++ b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml @@ -0,0 +1,129 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/gpu/host1x/nvidia,tegra20-host1x.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+title: Device tree binding for NVIDIA Host1x
+maintainers:
- Thierry Reding treding@gmail.com
- Mikko Perttunen mperttunen@nvidia.com
+properties:
- $nodename:
- pattern: "^host1x@[0-9a-f]*$"
- compatible:
- oneOf:
- const: nvidia,tegra20-host1x
- const: nvidia,tegra30-host1x
- const: nvidia,tegra114-host1x
- const: nvidia,tegra124-host1x
- items:
- const: nvidia,tegra132-host1x
- const: nvidia,tegra124-host1x
- const: nvidia,tegra210-host1x
- reg:
- maxItems: 1
- interrupts:
- items:
- description: Syncpoint threshold interrupt
- description: General interrupt
- interrupt-names:
- items:
- const: syncpt
- const: host1x
- clocks:
- maxItems: 1
- clock-names:
- items:
- const: host1x
- resets:
- maxItems: 1
- reset-names:
- items:
- const: host1x
- iommus:
- maxItems: 1
- interconnects:
- maxItems: 1
- interconnect-names:
- items:
- const: dma-mem
- '#address-cells':
- const: 1
- '#size-cells':
- const: 1
- ranges: true
+required:
- compatible
- reg
- interrupts
- interrupt-names
- clocks
- clock-names
- resets
- reset-names
- '#address-cells'
- '#size-cells'
- ranges
+additionalProperties:
- type: object
+if:
- properties:
- compatible:
contains:
anyOf:
- const: nvidia,tegra186-host1x
- const: nvidia,tegra194-host1x
Just use 'enum' instead of 'anyOf' and 'const'.
Yep, will fix.
+then:
- properties:
- reg:
items:
- description: Hypervisor-accessible register area
- description: VM-accessible register area
If you test this, it will fail due to the 'maxItems: 1' above. The main section has to pass for all conditions and then if/them schema add constraints.
Interesting, I did run the schema check and DTB check but I didn't see issues there. In any case, will fix.
- reg-names:
items:
- const: hypervisor
- const: vm
- required:
- reg-names
+examples:
- |
- #include <dt-bindings/clock/tegra20-car.h>
- #include <dt-bindings/interrupt-controller/arm-gic.h>
- host1x@50000000 {
compatible = "nvidia,tegra20-host1x";
reg = <0x50000000 0x00024000>;
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>, /* syncpt */
<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; /* general */
interrupt-names = "syncpt", "host1x";
clocks = <&tegra_car TEGRA20_CLK_HOST1X>;
clock-names = "host1x";
resets = <&tegra_car 28>;
reset-names = "host1x";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x54000000 0x54000000 0x04000000>;
- };
diff --git a/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml new file mode 100644 index 000000000000..9a6334d930c8 --- /dev/null +++ b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/gpu/host1x/nvidia,tegra210-nvdec.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+title: Device tree binding for NVIDIA Tegra VIC
I'm left wondering what NVDEC and VIC are?
Accidentally left VIC here. Will fix and add some more description.
FWIW, VIC is Video Image Compositor, and NVDEC is the HW video decoder on Tegra systems.
Thanks for reviewing!
Mikko
+maintainers:
- Thierry Reding treding@gmail.com
- Mikko Perttunen mperttunen@nvidia.com
+properties:
- $nodename:
- pattern: "^nvdec@[0-9a-f]*$"
- compatible:
- enum:
- nvidia,tegra210-nvdec
- nvidia,tegra186-nvdec
- nvidia,tegra194-nvdec
- reg:
- maxItems: 1
- clocks:
- maxItems: 1
- clock-names:
- items:
- const: nvdec
- resets:
- maxItems: 1
- reset-names:
- items:
- const: nvdec
- power-domains:
- maxItems: 1
- iommus:
- maxItems: 1
- interconnects:
- items:
- description: DMA read memory client
- description: DMA write memory client
- interconnect-names:
- items:
- const: dma-mem
- const: write
+required:
- compatible
- reg
- clocks
- clock-names
- resets
- reset-names
- power-domains
+additionalProperties: false
+examples:
- |
- #include <dt-bindings/clock/tegra186-clock.h>
- #include <dt-bindings/interrupt-controller/arm-gic.h>
- #include <dt-bindings/memory/tegra186-mc.h>
- #include <dt-bindings/power/tegra186-powergate.h>
- #include <dt-bindings/reset/tegra186-reset.h>
- nvdec@15480000 {
compatible = "nvidia,tegra186-nvdec";
reg = <0x15480000 0x40000>;
clocks = <&bpmp TEGRA186_CLK_NVDEC>;
clock-names = "nvdec";
resets = <&bpmp TEGRA186_RESET_NVDEC>;
reset-names = "nvdec";
power-domains = <&bpmp TEGRA186_POWER_DOMAIN_NVDEC>;
interconnects = <&mc TEGRA186_MEMORY_CLIENT_NVDECSRD &emc>,
<&mc TEGRA186_MEMORY_CLIENT_NVDECSWR &emc>;
interconnect-names = "dma-mem", "write";
iommus = <&smmu TEGRA186_SID_NVDEC>;
- };
diff --git a/MAINTAINERS b/MAINTAINERS index 8170b40d6236..b892419c6564 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5950,6 +5950,7 @@ L: linux-tegra@vger.kernel.org S: Supported T: git git://anongit.freedesktop.org/tegra/linux.git F: Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt +F: Documentation/devicetree/bindings/gpu/host1x/ F: drivers/gpu/drm/tegra/ F: drivers/gpu/host1x/ F: include/linux/host1x.h -- 2.30.0
On Thu, Feb 18, 2021 at 5:04 AM Mikko Perttunen cyndis@kapsi.fi wrote:
On 2/17/21 11:49 PM, Rob Herring wrote:
On Sat, Feb 13, 2021 at 12:15:10PM +0200, Mikko Perttunen wrote:
Convert the original Host1x bindings to YAML and add new bindings for NVDEC, now in a more appropriate location. The old text bindings for Host1x and engines are still kept at display/tegra/ since they encompass a lot more engines that haven't been converted over yet.
Signed-off-by: Mikko Perttunen mperttunen@nvidia.com
.../gpu/host1x/nvidia,tegra20-host1x.yaml | 129 ++++++++++++++++++ .../gpu/host1x/nvidia,tegra210-nvdec.yaml | 90 ++++++++++++ MAINTAINERS | 1 + 3 files changed, 220 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml create mode 100644 Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml
diff --git a/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml new file mode 100644 index 000000000000..613c6601f0f1 --- /dev/null +++ b/Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml @@ -0,0 +1,129 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/gpu/host1x/nvidia,tegra20-host1x.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+title: Device tree binding for NVIDIA Host1x
+maintainers:
- Thierry Reding treding@gmail.com
- Mikko Perttunen mperttunen@nvidia.com
+properties:
- $nodename:
- pattern: "^host1x@[0-9a-f]*$"
- compatible:
- oneOf:
- const: nvidia,tegra20-host1x
- const: nvidia,tegra30-host1x
- const: nvidia,tegra114-host1x
- const: nvidia,tegra124-host1x
- items:
- const: nvidia,tegra132-host1x
- const: nvidia,tegra124-host1x
- const: nvidia,tegra210-host1x
- reg:
- maxItems: 1
- interrupts:
- items:
- description: Syncpoint threshold interrupt
- description: General interrupt
- interrupt-names:
- items:
- const: syncpt
- const: host1x
- clocks:
- maxItems: 1
- clock-names:
- items:
- const: host1x
- resets:
- maxItems: 1
- reset-names:
- items:
- const: host1x
- iommus:
- maxItems: 1
- interconnects:
- maxItems: 1
- interconnect-names:
- items:
- const: dma-mem
- '#address-cells':
- const: 1
- '#size-cells':
- const: 1
- ranges: true
+required:
- compatible
- reg
- interrupts
- interrupt-names
- clocks
- clock-names
- resets
- reset-names
- '#address-cells'
- '#size-cells'
- ranges
+additionalProperties:
- type: object
+if:
- properties:
- compatible:
contains:
anyOf:
- const: nvidia,tegra186-host1x
- const: nvidia,tegra194-host1x
Just use 'enum' instead of 'anyOf' and 'const'.
Yep, will fix.
+then:
- properties:
- reg:
items:
- description: Hypervisor-accessible register area
- description: VM-accessible register area
If you test this, it will fail due to the 'maxItems: 1' above. The main section has to pass for all conditions and then if/them schema add constraints.
Interesting, I did run the schema check and DTB check but I didn't see issues there. In any case, will fix.
It may pass if you had 'reg = <base1 size1 base2 size2>' rather than 'reg = <base1 size1>, <base2 size2>'. While the bracketing doesn't matter for dtbs, it does currently for the schema.
Rob
Add a device tree node for NVDEC on Tegra186.
Signed-off-by: Mikko Perttunen mperttunen@nvidia.com --- arch/arm64/boot/dts/nvidia/tegra186.dtsi | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/arch/arm64/boot/dts/nvidia/tegra186.dtsi b/arch/arm64/boot/dts/nvidia/tegra186.dtsi index 58c51965df47..4bb6fbe6b9ce 100644 --- a/arch/arm64/boot/dts/nvidia/tegra186.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra186.dtsi @@ -1340,6 +1340,21 @@ dsib: dsi@15400000 { power-domains = <&bpmp TEGRA186_POWER_DOMAIN_DISP>; };
+ nvdec@15480000 { + compatible = "nvidia,tegra186-nvdec"; + reg = <0x15480000 0x40000>; + clocks = <&bpmp TEGRA186_CLK_NVDEC>; + clock-names = "nvdec"; + resets = <&bpmp TEGRA186_RESET_NVDEC>; + reset-names = "nvdec"; + + power-domains = <&bpmp TEGRA186_POWER_DOMAIN_NVDEC>; + interconnects = <&mc TEGRA186_MEMORY_CLIENT_NVDECSRD &emc>, + <&mc TEGRA186_MEMORY_CLIENT_NVDECSWR &emc>; + interconnect-names = "dma-mem", "write"; + iommus = <&smmu TEGRA186_SID_NVDEC>; + }; + sor0: sor@15540000 { compatible = "nvidia,tegra186-sor"; reg = <0x15540000 0x10000>;
Add support for booting and using NVDEC on Tegra210, Tegra186 and Tegra194 to the Host1x and TegraDRM drivers. Booting in secure mode is not currently supported.
Signed-off-by: Mikko Perttunen mperttunen@nvidia.com --- drivers/gpu/drm/tegra/Makefile | 3 +- drivers/gpu/drm/tegra/drm.c | 4 + drivers/gpu/drm/tegra/drm.h | 1 + drivers/gpu/drm/tegra/nvdec.c | 497 +++++++++++++++++++++++++++++++++ drivers/gpu/host1x/dev.c | 12 + include/linux/host1x.h | 1 + 6 files changed, 517 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/tegra/nvdec.c
diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile index 4e3295f436f1..a736bb5e5376 100644 --- a/drivers/gpu/drm/tegra/Makefile +++ b/drivers/gpu/drm/tegra/Makefile @@ -24,7 +24,8 @@ tegra-drm-y := \ gr2d.o \ gr3d.o \ falcon.o \ - vic.o + vic.o \ + nvdec.o
tegra-drm-y += trace.o
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 60eab403ae9b..accc41bff173 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -1338,15 +1338,18 @@ static const struct of_device_id host1x_drm_subdevs[] = { { .compatible = "nvidia,tegra210-sor", }, { .compatible = "nvidia,tegra210-sor1", }, { .compatible = "nvidia,tegra210-vic", }, + { .compatible = "nvidia,tegra210-nvdec", }, { .compatible = "nvidia,tegra186-display", }, { .compatible = "nvidia,tegra186-dc", }, { .compatible = "nvidia,tegra186-sor", }, { .compatible = "nvidia,tegra186-sor1", }, { .compatible = "nvidia,tegra186-vic", }, + { .compatible = "nvidia,tegra186-nvdec", }, { .compatible = "nvidia,tegra194-display", }, { .compatible = "nvidia,tegra194-dc", }, { .compatible = "nvidia,tegra194-sor", }, { .compatible = "nvidia,tegra194-vic", }, + { .compatible = "nvidia,tegra194-nvdec", }, { /* sentinel */ } };
@@ -1370,6 +1373,7 @@ static struct platform_driver * const drivers[] = { &tegra_gr2d_driver, &tegra_gr3d_driver, &tegra_vic_driver, + &tegra_nvdec_driver, };
static int __init host1x_drm_init(void) diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 1af57c2016eb..ba52718a48bd 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -194,5 +194,6 @@ extern struct platform_driver tegra_sor_driver; extern struct platform_driver tegra_gr2d_driver; extern struct platform_driver tegra_gr3d_driver; extern struct platform_driver tegra_vic_driver; +extern struct platform_driver tegra_nvdec_driver;
#endif /* HOST1X_DRM_H */ diff --git a/drivers/gpu/drm/tegra/nvdec.c b/drivers/gpu/drm/tegra/nvdec.c new file mode 100644 index 000000000000..0b78ee81d01f --- /dev/null +++ b/drivers/gpu/drm/tegra/nvdec.c @@ -0,0 +1,497 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2021, NVIDIA Corporation. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/host1x.h> +#include <linux/iommu.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> + +#include <soc/tegra/pmc.h> + +#include "drm.h" +#include "falcon.h" +#include "vic.h" + +struct nvdec_config { + const char *firmware; + unsigned int version; + bool supports_sid; +}; + +struct nvdec { + struct falcon falcon; + + void __iomem *regs; + struct tegra_drm_client client; + struct host1x_channel *channel; + struct device *dev; + struct clk *clk; + struct reset_control *rst; + + /* Platform configuration */ + const struct nvdec_config *config; +}; + +static inline struct nvdec *to_vic(struct tegra_drm_client *client) +{ + return container_of(client, struct nvdec, client); +} + +static void nvdec_writel(struct nvdec *nvdec, u32 value, unsigned int offset) +{ + writel(value, nvdec->regs + offset); +} + +static int nvdec_boot(struct nvdec *nvdec) +{ +#ifdef CONFIG_IOMMU_API + struct iommu_fwspec *spec = dev_iommu_fwspec_get(nvdec->dev); +#endif + int err = 0; + +#ifdef CONFIG_IOMMU_API + if (nvdec->config->supports_sid && spec) { + u32 value; + + value = TRANSCFG_ATT(1, TRANSCFG_SID_FALCON) | + TRANSCFG_ATT(0, TRANSCFG_SID_HW); + nvdec_writel(nvdec, value, VIC_TFBIF_TRANSCFG); + + if (spec->num_ids > 0) { + value = spec->ids[0] & 0xffff; + + nvdec_writel(nvdec, value, VIC_THI_STREAMID0); + nvdec_writel(nvdec, value, VIC_THI_STREAMID1); + } + } +#endif + + err = falcon_boot(&nvdec->falcon); + if (err < 0) + return err; + + err = falcon_wait_idle(&nvdec->falcon); + if (err < 0) { + dev_err(nvdec->dev, + "failed to set application ID and FCE base\n"); + return err; + } + + return 0; +} + +static int nvdec_init(struct host1x_client *client) +{ + struct tegra_drm_client *drm = host1x_to_drm_client(client); + struct drm_device *dev = dev_get_drvdata(client->host); + struct tegra_drm *tegra = dev->dev_private; + struct nvdec *nvdec = to_vic(drm); + int err; + + err = host1x_client_iommu_attach(client); + if (err < 0 && err != -ENODEV) { + dev_err(nvdec->dev, "failed to attach to domain: %d\n", err); + return err; + } + + nvdec->channel = host1x_channel_request(client); + if (!nvdec->channel) { + err = -ENOMEM; + goto detach; + } + + client->syncpts[0] = host1x_syncpt_request(client, 0); + if (!client->syncpts[0]) { + err = -ENOMEM; + goto free_channel; + } + + err = tegra_drm_register_client(tegra, drm); + if (err < 0) + goto free_syncpt; + + /* + * Inherit the DMA parameters (such as maximum segment size) from the + * parent host1x device. + */ + client->dev->dma_parms = client->host->dma_parms; + + return 0; + +free_syncpt: + host1x_syncpt_put(client->syncpts[0]); +free_channel: + host1x_channel_put(nvdec->channel); +detach: + host1x_client_iommu_detach(client); + + return err; +} + +static int nvdec_exit(struct host1x_client *client) +{ + struct tegra_drm_client *drm = host1x_to_drm_client(client); + struct drm_device *dev = dev_get_drvdata(client->host); + struct tegra_drm *tegra = dev->dev_private; + struct nvdec *nvdec = to_vic(drm); + int err; + + /* avoid a dangling pointer just in case this disappears */ + client->dev->dma_parms = NULL; + + err = tegra_drm_unregister_client(tegra, drm); + if (err < 0) + return err; + + host1x_syncpt_put(client->syncpts[0]); + host1x_channel_put(nvdec->channel); + host1x_client_iommu_detach(client); + + if (client->group) { + dma_unmap_single(nvdec->dev, nvdec->falcon.firmware.phys, + nvdec->falcon.firmware.size, DMA_TO_DEVICE); + tegra_drm_free(tegra, nvdec->falcon.firmware.size, + nvdec->falcon.firmware.virt, + nvdec->falcon.firmware.iova); + } else { + dma_free_coherent(nvdec->dev, nvdec->falcon.firmware.size, + nvdec->falcon.firmware.virt, + nvdec->falcon.firmware.iova); + } + + return 0; +} + +static const struct host1x_client_ops nvdec_client_ops = { + .init = nvdec_init, + .exit = nvdec_exit, +}; + +static int nvdec_load_firmware(struct nvdec *nvdec) +{ + struct host1x_client *client = &nvdec->client.base; + struct tegra_drm *tegra = nvdec->client.drm; + dma_addr_t iova; + size_t size; + void *virt; + int err; + + if (nvdec->falcon.firmware.virt) + return 0; + + err = falcon_read_firmware(&nvdec->falcon, nvdec->config->firmware); + if (err < 0) + return err; + + size = nvdec->falcon.firmware.size; + + if (!client->group) { + virt = dma_alloc_coherent(nvdec->dev, size, &iova, GFP_KERNEL); + + err = dma_mapping_error(nvdec->dev, iova); + if (err < 0) + return err; + } else { + virt = tegra_drm_alloc(tegra, size, &iova); + } + + nvdec->falcon.firmware.virt = virt; + nvdec->falcon.firmware.iova = iova; + + err = falcon_load_firmware(&nvdec->falcon); + if (err < 0) + goto cleanup; + + /* + * In this case we have received an IOVA from the shared domain, so we + * need to make sure to get the physical address so that the DMA API + * knows what memory pages to flush the cache for. + */ + if (client->group) { + dma_addr_t phys; + + phys = dma_map_single(nvdec->dev, virt, size, DMA_TO_DEVICE); + + err = dma_mapping_error(nvdec->dev, phys); + if (err < 0) + goto cleanup; + + nvdec->falcon.firmware.phys = phys; + } + + return 0; + +cleanup: + if (!client->group) + dma_free_coherent(nvdec->dev, size, virt, iova); + else + tegra_drm_free(tegra, size, virt, iova); + + return err; +} + + +static int nvdec_runtime_resume(struct device *dev) +{ + struct nvdec *nvdec = dev_get_drvdata(dev); + int err; + + err = clk_prepare_enable(nvdec->clk); + if (err < 0) + return err; + + usleep_range(10, 20); + + err = reset_control_deassert(nvdec->rst); + if (err < 0) + goto disable; + + usleep_range(10, 20); + + err = nvdec_load_firmware(nvdec); + if (err < 0) + goto assert; + + err = nvdec_boot(nvdec); + if (err < 0) + goto assert; + + return 0; + +assert: + reset_control_assert(nvdec->rst); +disable: + clk_disable_unprepare(nvdec->clk); + return err; +} + +static int nvdec_runtime_suspend(struct device *dev) +{ + struct nvdec *nvdec = dev_get_drvdata(dev); + int err; + + err = reset_control_assert(nvdec->rst); + if (err < 0) + return err; + + usleep_range(2000, 4000); + + clk_disable_unprepare(nvdec->clk); + + return 0; +} + +static int nvdec_open_channel(struct tegra_drm_client *client, + struct tegra_drm_context *context) +{ + struct nvdec *nvdec = to_vic(client); + int err; + + err = pm_runtime_get_sync(nvdec->dev); + if (err < 0) { + pm_runtime_put(nvdec->dev); + return err; + } + + context->channel = host1x_channel_get(nvdec->channel); + if (!context->channel) { + pm_runtime_put(nvdec->dev); + return -ENOMEM; + } + + return 0; +} + +static void nvdec_close_channel(struct tegra_drm_context *context) +{ + struct nvdec *nvdec = to_vic(context->client); + + host1x_channel_put(context->channel); + pm_runtime_put(nvdec->dev); +} + +static const struct tegra_drm_client_ops nvdec_ops = { + .open_channel = nvdec_open_channel, + .close_channel = nvdec_close_channel, + .submit = tegra_drm_submit, +}; + +#define NVIDIA_TEGRA_210_NVDEC_FIRMWARE "nvidia/tegra210/nvdec.bin" + +static const struct nvdec_config nvdec_t210_config = { + .firmware = NVIDIA_TEGRA_210_NVDEC_FIRMWARE, + .version = 0x21, + .supports_sid = false, +}; + +#define NVIDIA_TEGRA_186_NVDEC_FIRMWARE "nvidia/tegra186/nvdec.bin" + +static const struct nvdec_config nvdec_t186_config = { + .firmware = NVIDIA_TEGRA_186_NVDEC_FIRMWARE, + .version = 0x18, + .supports_sid = true, +}; + +#define NVIDIA_TEGRA_194_NVDEC_FIRMWARE "nvidia/tegra194/nvdec.bin" + +static const struct nvdec_config nvdec_t194_config = { + .firmware = NVIDIA_TEGRA_194_NVDEC_FIRMWARE, + .version = 0x19, + .supports_sid = true, +}; + +static const struct of_device_id tegra_nvdec_of_match[] = { + { .compatible = "nvidia,tegra210-nvdec", .data = &nvdec_t210_config }, + { .compatible = "nvidia,tegra186-nvdec", .data = &nvdec_t186_config }, + { .compatible = "nvidia,tegra194-nvdec", .data = &nvdec_t194_config }, + { }, +}; +MODULE_DEVICE_TABLE(of, tegra_nvdec_of_match); + +static int nvdec_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct host1x_syncpt **syncpts; + struct resource *regs; + struct nvdec *nvdec; + int err; + + /* inherit DMA mask from host1x parent */ + err = dma_coerce_mask_and_coherent(dev, *dev->parent->dma_mask); + if (err < 0) { + dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err); + return err; + } + + nvdec = devm_kzalloc(dev, sizeof(*nvdec), GFP_KERNEL); + if (!nvdec) + return -ENOMEM; + + nvdec->config = of_device_get_match_data(dev); + + syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL); + if (!syncpts) + return -ENOMEM; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_err(&pdev->dev, "failed to get registers\n"); + return -ENXIO; + } + + nvdec->regs = devm_ioremap_resource(dev, regs); + if (IS_ERR(nvdec->regs)) + return PTR_ERR(nvdec->regs); + + nvdec->clk = devm_clk_get(dev, NULL); + if (IS_ERR(nvdec->clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + return PTR_ERR(nvdec->clk); + } + + if (!dev->pm_domain) { + nvdec->rst = devm_reset_control_get(dev, "nvdec"); + if (IS_ERR(nvdec->rst)) { + dev_err(&pdev->dev, "failed to get reset\n"); + return PTR_ERR(nvdec->rst); + } + } + + nvdec->falcon.dev = dev; + nvdec->falcon.regs = nvdec->regs; + + err = falcon_init(&nvdec->falcon); + if (err < 0) + return err; + + platform_set_drvdata(pdev, nvdec); + + INIT_LIST_HEAD(&nvdec->client.base.list); + nvdec->client.base.ops = &nvdec_client_ops; + nvdec->client.base.dev = dev; + nvdec->client.base.class = HOST1X_CLASS_NVDEC; + nvdec->client.base.syncpts = syncpts; + nvdec->client.base.num_syncpts = 1; + nvdec->dev = dev; + + INIT_LIST_HEAD(&nvdec->client.list); + nvdec->client.version = nvdec->config->version; + nvdec->client.ops = &nvdec_ops; + + err = host1x_client_register(&nvdec->client.base); + if (err < 0) { + dev_err(dev, "failed to register host1x client: %d\n", err); + goto exit_falcon; + } + + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + err = nvdec_runtime_resume(&pdev->dev); + if (err < 0) + goto unregister_client; + } + + return 0; + +unregister_client: + host1x_client_unregister(&nvdec->client.base); +exit_falcon: + falcon_exit(&nvdec->falcon); + + return err; +} + +static int nvdec_remove(struct platform_device *pdev) +{ + struct nvdec *nvdec = platform_get_drvdata(pdev); + int err; + + err = host1x_client_unregister(&nvdec->client.base); + if (err < 0) { + dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", + err); + return err; + } + + if (pm_runtime_enabled(&pdev->dev)) + pm_runtime_disable(&pdev->dev); + else + nvdec_runtime_suspend(&pdev->dev); + + falcon_exit(&nvdec->falcon); + + return 0; +} + +static const struct dev_pm_ops nvdec_pm_ops = { + SET_RUNTIME_PM_OPS(nvdec_runtime_suspend, nvdec_runtime_resume, NULL) +}; + +struct platform_driver tegra_nvdec_driver = { + .driver = { + .name = "tegra-nvdec", + .of_match_table = tegra_nvdec_of_match, + .pm = &nvdec_pm_ops + }, + .probe = nvdec_probe, + .remove = nvdec_remove, +}; + +#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) +MODULE_FIRMWARE(NVIDIA_TEGRA_210_NVDEC_FIRMWARE); +#endif +#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) +MODULE_FIRMWARE(NVIDIA_TEGRA_186_NVDEC_FIRMWARE); +#endif +#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) +MODULE_FIRMWARE(NVIDIA_TEGRA_194_NVDEC_FIRMWARE); +#endif diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 8b50fbb22846..121241332876 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -132,6 +132,12 @@ static const struct host1x_sid_entry tegra186_sid_table[] = { .offset = 0x30, .limit = 0x34 }, + { + /* NVDEC */ + .base = 0x1b00, + .offset = 0x30, + .limit = 0x34 + }, };
static const struct host1x_info host1x06_info = { @@ -156,6 +162,12 @@ static const struct host1x_sid_entry tegra194_sid_table[] = { .offset = 0x30, .limit = 0x34 }, + { + /* NVDEC */ + .base = 0x1b00, + .offset = 0x30, + .limit = 0x34 + }, };
static const struct host1x_info host1x07_info = { diff --git a/include/linux/host1x.h b/include/linux/host1x.h index a1d9cee8bead..17de9540e18e 100644 --- a/include/linux/host1x.h +++ b/include/linux/host1x.h @@ -15,6 +15,7 @@ enum host1x_class { HOST1X_CLASS_GR2D_SB = 0x52, HOST1X_CLASS_VIC = 0x5D, HOST1X_CLASS_GR3D = 0x60, + HOST1X_CLASS_NVDEC = 0xF0, };
struct host1x;
Hi Mikko,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on tegra/for-next] [also build test ERROR on robh/for-next tegra-drm/drm/tegra/for-next v5.11-rc7 next-20210212] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Mikko-Perttunen/NVIDIA-Tegra-NVDEC-... base: https://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git for-next config: arm-defconfig (attached as .config) compiler: arm-linux-gnueabi-gcc (GCC) 9.3.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/5951327b2039bedd20ca3e7837d4cb6021dc... git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Mikko-Perttunen/NVIDIA-Tegra-NVDEC-support/20210213-181808 git checkout 5951327b2039bedd20ca3e7837d4cb6021dc9777 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arm
If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot lkp@intel.com
All errors (new ones prefixed by >>):
drivers/gpu/drm/tegra/nvdec.c: In function 'nvdec_init':
drivers/gpu/drm/tegra/nvdec.c:131:2: error: implicit declaration of function 'host1x_syncpt_put'; did you mean 'host1x_syncpt_get'? [-Werror=implicit-function-declaration]
131 | host1x_syncpt_put(client->syncpts[0]); | ^~~~~~~~~~~~~~~~~ | host1x_syncpt_get cc1: some warnings being treated as errors
vim +131 drivers/gpu/drm/tegra/nvdec.c
91 92 static int nvdec_init(struct host1x_client *client) 93 { 94 struct tegra_drm_client *drm = host1x_to_drm_client(client); 95 struct drm_device *dev = dev_get_drvdata(client->host); 96 struct tegra_drm *tegra = dev->dev_private; 97 struct nvdec *nvdec = to_vic(drm); 98 int err; 99 100 err = host1x_client_iommu_attach(client); 101 if (err < 0 && err != -ENODEV) { 102 dev_err(nvdec->dev, "failed to attach to domain: %d\n", err); 103 return err; 104 } 105 106 nvdec->channel = host1x_channel_request(client); 107 if (!nvdec->channel) { 108 err = -ENOMEM; 109 goto detach; 110 } 111 112 client->syncpts[0] = host1x_syncpt_request(client, 0); 113 if (!client->syncpts[0]) { 114 err = -ENOMEM; 115 goto free_channel; 116 } 117 118 err = tegra_drm_register_client(tegra, drm); 119 if (err < 0) 120 goto free_syncpt; 121 122 /* 123 * Inherit the DMA parameters (such as maximum segment size) from the 124 * parent host1x device. 125 */ 126 client->dev->dma_parms = client->host->dma_parms; 127 128 return 0; 129 130 free_syncpt:
131 host1x_syncpt_put(client->syncpts[0]);
132 free_channel: 133 host1x_channel_put(nvdec->channel); 134 detach: 135 host1x_client_iommu_detach(client); 136 137 return err; 138 } 139
--- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
On 13/02/2021 10:15, Mikko Perttunen wrote:
Add support for booting and using NVDEC on Tegra210, Tegra186 and Tegra194 to the Host1x and TegraDRM drivers. Booting in secure mode is not currently supported.
Signed-off-by: Mikko Perttunen mperttunen@nvidia.com
drivers/gpu/drm/tegra/Makefile | 3 +- drivers/gpu/drm/tegra/drm.c | 4 + drivers/gpu/drm/tegra/drm.h | 1 + drivers/gpu/drm/tegra/nvdec.c | 497 +++++++++++++++++++++++++++++++++ drivers/gpu/host1x/dev.c | 12 + include/linux/host1x.h | 1 + 6 files changed, 517 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/tegra/nvdec.c
...
+static int nvdec_probe(struct platform_device *pdev) +{
- struct device *dev = &pdev->dev;
- struct host1x_syncpt **syncpts;
- struct resource *regs;
- struct nvdec *nvdec;
- int err;
- /* inherit DMA mask from host1x parent */
- err = dma_coerce_mask_and_coherent(dev, *dev->parent->dma_mask);
- if (err < 0) {
dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err);
return err;
- }
- nvdec = devm_kzalloc(dev, sizeof(*nvdec), GFP_KERNEL);
- if (!nvdec)
return -ENOMEM;
- nvdec->config = of_device_get_match_data(dev);
- syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL);
- if (!syncpts)
return -ENOMEM;
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!regs) {
dev_err(&pdev->dev, "failed to get registers\n");
return -ENXIO;
- }
- nvdec->regs = devm_ioremap_resource(dev, regs);
- if (IS_ERR(nvdec->regs))
return PTR_ERR(nvdec->regs);
We should be able to use devm_platform_get_and_ioremap_resource() here.
- nvdec->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(nvdec->clk)) {
dev_err(&pdev->dev, "failed to get clock\n");
return PTR_ERR(nvdec->clk);
- }
- if (!dev->pm_domain) {
Looks like the power-domain is required by device-tree and so do we need this?
nvdec->rst = devm_reset_control_get(dev, "nvdec");
if (IS_ERR(nvdec->rst)) {
dev_err(&pdev->dev, "failed to get reset\n");
return PTR_ERR(nvdec->rst);
}
- }
- nvdec->falcon.dev = dev;
- nvdec->falcon.regs = nvdec->regs;
- err = falcon_init(&nvdec->falcon);
- if (err < 0)
return err;
- platform_set_drvdata(pdev, nvdec);
- INIT_LIST_HEAD(&nvdec->client.base.list);
- nvdec->client.base.ops = &nvdec_client_ops;
- nvdec->client.base.dev = dev;
- nvdec->client.base.class = HOST1X_CLASS_NVDEC;
- nvdec->client.base.syncpts = syncpts;
- nvdec->client.base.num_syncpts = 1;
- nvdec->dev = dev;
- INIT_LIST_HEAD(&nvdec->client.list);
- nvdec->client.version = nvdec->config->version;
- nvdec->client.ops = &nvdec_ops;
- err = host1x_client_register(&nvdec->client.base);
- if (err < 0) {
dev_err(dev, "failed to register host1x client: %d\n", err);
goto exit_falcon;
- }
- pm_runtime_enable(&pdev->dev);
- if (!pm_runtime_enabled(&pdev->dev)) {
err = nvdec_runtime_resume(&pdev->dev);
if (err < 0)
goto unregister_client;
- }
pm_runtime should always be enabled for 64-bit Tegra and so we should not need to check pm_runtime_enabled().
Cheers Jon
Hi,
On 13/02/2021 11:15, Mikko Perttunen wrote:
Hi all,
with the release of documentation headers for Tegra multimedia engines (NVDEC, NVENC, NVJPG) [1], I have started working on the corresponding implementations. Here's the first one, NVDEC.
The kernel driver is a simple Falcon boot driver based on the VIC driver. Some code sharing should be considered there in the future. The userspace driver to accompany this is a bit more complicated - I have expanded vaapi-tegra-driver[2] to support MPEG2 decoding. It should be noted that the implementation is still very clunky and has poor performance, but it's a start.
Funny how all this tries to avoid all the DRM, remoteproc, V4L2-M2M stateless & co all the other vendors tries to make usage of...
Neil
This series is based on top of the "Host1x/TegraDRM UAPI" series. For testing, appropriate firmware should be obtained from a Linux for Tegra distribution for now; the GPU should also be enabled in the device tree.
Series was tested on Tegra186.
Thanks!
Mikko
[1] https://github.com/NVIDIA/open-gpu-doc/tree/master/classes/video [2] https://github.com/cyndis/vaapi-tegra-driver
Mikko Perttunen (3): dt-bindings: Add YAML bindings for Host1x and NVDEC arm64: tegra: Add NVDEC to Tegra186 device tree drm/tegra: Add NVDEC driver
.../gpu/host1x/nvidia,tegra20-host1x.yaml | 129 +++++ .../gpu/host1x/nvidia,tegra210-nvdec.yaml | 90 ++++ MAINTAINERS | 1 + arch/arm64/boot/dts/nvidia/tegra186.dtsi | 15 + drivers/gpu/drm/tegra/Makefile | 3 +- drivers/gpu/drm/tegra/drm.c | 4 + drivers/gpu/drm/tegra/drm.h | 1 + drivers/gpu/drm/tegra/nvdec.c | 497 ++++++++++++++++++ drivers/gpu/host1x/dev.c | 12 + include/linux/host1x.h | 1 + 10 files changed, 752 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra20-host1x.yaml create mode 100644 Documentation/devicetree/bindings/gpu/host1x/nvidia,tegra210-nvdec.yaml create mode 100644 drivers/gpu/drm/tegra/nvdec.c
On Mon, Feb 15, 2021 at 10:10:26AM +0100, Neil Armstrong wrote:
Hi,
On 13/02/2021 11:15, Mikko Perttunen wrote:
Hi all,
with the release of documentation headers for Tegra multimedia engines (NVDEC, NVENC, NVJPG) [1], I have started working on the corresponding implementations. Here's the first one, NVDEC.
The kernel driver is a simple Falcon boot driver based on the VIC driver. Some code sharing should be considered there in the future. The userspace driver to accompany this is a bit more complicated - I have expanded vaapi-tegra-driver[2] to support MPEG2 decoding. It should be noted that the implementation is still very clunky and has poor performance, but it's a start.
Funny how all this tries to avoid all the DRM, remoteproc, V4L2-M2M stateless & co all the other vendors tries to make usage of...
Care to elaborate why you think this is trying to avoid anything? Mikko pointed you at the documentation for these engines, provided a link to an open-source (albeit work in progress) userspace driver and posts an extension to an existing DRM driver to add the required kernel functionality. That's a standard approach for submitting this kind of driver.
Thierry
Hi Thierry,
On 15/02/2021 10:50, Thierry Reding wrote:
On Mon, Feb 15, 2021 at 10:10:26AM +0100, Neil Armstrong wrote:
Hi,
On 13/02/2021 11:15, Mikko Perttunen wrote:
Hi all,
with the release of documentation headers for Tegra multimedia engines (NVDEC, NVENC, NVJPG) [1], I have started working on the corresponding implementations. Here's the first one, NVDEC.
The kernel driver is a simple Falcon boot driver based on the VIC driver. Some code sharing should be considered there in the future. The userspace driver to accompany this is a bit more complicated - I have expanded vaapi-tegra-driver[2] to support MPEG2 decoding. It should be noted that the implementation is still very clunky and has poor performance, but it's a start.
Funny how all this tries to avoid all the DRM, remoteproc, V4L2-M2M stateless & co all the other vendors tries to make usage of...
Care to elaborate why you think this is trying to avoid anything? Mikko pointed you at the documentation for these engines, provided a link to an open-source (albeit work in progress) userspace driver and posts an extension to an existing DRM driver to add the required kernel functionality. That's a standard approach for submitting this kind of driver.
Thanks for the reply, I didn't look extensively at all the documents & userspace libraries, but I wonder why this couldn't fit in the V4L2-M2M approach and avoid having userspace drivers and specific libraries to handle this.
Neil
Thierry
On Mon, Feb 15, 2021 at 11:21:27AM +0100, Neil Armstrong wrote:
Hi Thierry,
On 15/02/2021 10:50, Thierry Reding wrote:
On Mon, Feb 15, 2021 at 10:10:26AM +0100, Neil Armstrong wrote:
Hi,
On 13/02/2021 11:15, Mikko Perttunen wrote:
Hi all,
with the release of documentation headers for Tegra multimedia engines (NVDEC, NVENC, NVJPG) [1], I have started working on the corresponding implementations. Here's the first one, NVDEC.
The kernel driver is a simple Falcon boot driver based on the VIC driver. Some code sharing should be considered there in the future. The userspace driver to accompany this is a bit more complicated - I have expanded vaapi-tegra-driver[2] to support MPEG2 decoding. It should be noted that the implementation is still very clunky and has poor performance, but it's a start.
Funny how all this tries to avoid all the DRM, remoteproc, V4L2-M2M stateless & co all the other vendors tries to make usage of...
Care to elaborate why you think this is trying to avoid anything? Mikko pointed you at the documentation for these engines, provided a link to an open-source (albeit work in progress) userspace driver and posts an extension to an existing DRM driver to add the required kernel functionality. That's a standard approach for submitting this kind of driver.
Thanks for the reply, I didn't look extensively at all the documents & userspace libraries, but I wonder why this couldn't fit in the V4L2-M2M approach and avoid having userspace drivers and specific libraries to handle this.
Ah, I see. Without going too much into the details, the reason for this is that the multimedia engines on Tegra use host1x for command submission. host1x is roughly a command stream parser with built-in capability for synchronization and (in newer generations) process isolation, etc. This same engine is used for things like 2D and 3D acceleration on older chips and there are other hardware blocks that use it, such as the video image compositor (used for some post-processing tasks). The GPU can also interoperate with host1x for synchronization with these multimedia engines.
The userspace interfaces for 2D and 3D have existed for a long time, and the fundamental programming sequences are largely the same, so we chose to use the same interface for simplicity rather that duplicating most of this into the kernel.
Constructing these command streams can be fairly complicated and a number of extra data structures are needed for each command. Putting all of that into userspace reduces the potential for bugs and crashes in the kernel that may take down the whole system.
As for the userspace drivers argument, this isn't adding anything new but rather provides a driver for the existing VAAPI library that's already widely supported in multimedia applications.
Thierry
dri-devel@lists.freedesktop.org