Devicetree
 help / color / mirror / Atom feed
* [PATCH 0/3] nvmem: allow specifying cells by just names in DT
From: Rafał Miłecki @ 2022-01-24 16:02 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring
  Cc: Florian Fainelli, Hauke Mehrtens, bcm-kernel-feedback-list,
	devicetree, linux-arm-kernel, linux-kernel,
	Rafał Miłecki

From: Rafał Miłecki <rafal@milecki.pl>

This is a simplified & cleaned up version of my:
[PATCH 0/5] nvmem: support more NVMEM cells variants

These changes will allow me to improve BCM5301X support with:

diff --git a/arch/arm/boot/dts/bcm47094-luxul-xwr-3150-v1.dts b/arch/arm/boot/dts/bcm47094-luxul-xwr-3150-v1.dts
index 24ae3c8a3..9efcb2424 100644
--- a/arch/arm/boot/dts/bcm47094-luxul-xwr-3150-v1.dts
+++ b/arch/arm/boot/dts/bcm47094-luxul-xwr-3150-v1.dts
@@ -25,6 +25,9 @@ memory@0 {
 	nvram@1eff0000 {
 		compatible = "brcm,nvram";
 		reg = <0x1eff0000 0x10000>;
+
+		et0macaddr: et0macaddr {
+		};
 	};
 
 	leds {
@@ -72,6 +75,11 @@ restart {
 	};
 };
 
+&gmac0 {
+	nvmem-cells = <&et0macaddr>;
+	nvmem-cell-names = "mac-address";
+};
+
 &usb3 {
 	vcc-gpio = <&chipcommon 18 GPIO_ACTIVE_HIGH>;
 };

Rafał Miłecki (3):
  dt-bindings: nvmem: make "reg" property optional
  dt-bindings: nvmem: brcm,nvram: add NVMEM cell to example
  nvmem: core: add cell name based matching of DT cell nodes

 .../devicetree/bindings/nvmem/brcm,nvram.yaml |  7 +++--
 .../devicetree/bindings/nvmem/nvmem.yaml      |  3 ---
 drivers/nvmem/core.c                          | 27 +++++++++++++++++++
 3 files changed, 32 insertions(+), 5 deletions(-)

-- 
2.31.1


^ permalink raw reply related

* Re: [PATCH 1/6] dt-bindings: input: touchscreen: add bindings for focaltech,fts
From: Rob Herring @ 2022-01-24 16:01 UTC (permalink / raw)
  To: Caleb Connolly
  Cc: Henrik Rydberg, linux-kernel, Colin Cross, linux-input,
	Sam Ravnborg, Rob Herring, Andy Gross, linux-arm-msm, Kees Cook,
	Alexander Martinz, David Airlie, Harigovindan P, Dmitry Torokhov,
	Daniel Vetter, Anton Vorontsov, Bjorn Andersson, Tony Luck,
	dri-devel, devicetree, Thierry Reding
In-Reply-To: <20220123173650.290349-2-caleb@connolly.tech>

On Sun, 23 Jan 2022 17:37:27 +0000, Caleb Connolly wrote:
> Add devicetree bindings for the Focaltech FTS touchscreen drivers.
> 
> Signed-off-by: Caleb Connolly <caleb@connolly.tech>
> ---
>  .../input/touchscreen/focaltech,fts.yaml      | 78 +++++++++++++++++++
>  1 file changed, 78 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/input/touchscreen/focaltech,fts.yaml
> 

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:

dtschema/dtc warnings/errors:
Error: Documentation/devicetree/bindings/input/touchscreen/focaltech,fts.example.dts:21.9-14 syntax error
FATAL ERROR: Unable to parse input tree
make[1]: *** [scripts/Makefile.lib:378: Documentation/devicetree/bindings/input/touchscreen/focaltech,fts.example.dt.yaml] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:1398: dt_binding_check] Error 2

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/patch/1583161

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.


^ permalink raw reply

* Re: [PATCH v3 3/5] dt-bindings: bus: add device tree bindings for qcom,ssc-block-bus
From: Rob Herring @ 2022-01-24 16:01 UTC (permalink / raw)
  To: michael.srba
  Cc: Rob Herring, Philipp Zabel, devicetree, Michael Srba,
	Linus Walleij, linux-arm-msm, Andy Gross, Saravana Kannan,
	Bjorn Andersson, Florian Fainelli, Arnd Bergmann,
	Greg Kroah-Hartman, Stephen Boyd
In-Reply-To: <20220124121853.23600-3-michael.srba@seznam.cz>

On Mon, 24 Jan 2022 13:18:51 +0100, michael.srba@seznam.cz wrote:
> From: Michael Srba <Michael.Srba@seznam.cz>
> 
>  This patch adds bindings for the AHB bus which exposes the SCC block in
>  the global address space. This bus (and the SSC block itself) is present
>  on certain qcom SoCs.
> 
>  In typical configuration, this bus (as some of the clocks and registers
>  that we need to manipulate) is not accessible to the OS, and the
>  resources on this bus are indirectly accessed by communicating with a
>  hexagon CPU core residing in the SSC block. In this configuration, the
>  hypervisor is the one performing the bus initialization for the purposes
>  of bringing the haxagon CPU core out of reset.
> 
>  However, it is possible to change the configuration, in which case this
>  binding serves to allow the OS to initialize the bus.
> 
> Signed-off-by: Michael Srba <Michael.Srba@seznam.cz>
> ---
>  CHANGES:
>  - v2: fix issues caught by by dt-schema
>  - v3: none
> ---
>  Documentation/devicetree/bindings/bus/qcom,ssc-block-bus.yaml | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 159 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/bus/qcom,ssc-block-bus.yaml
> 

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:
./Documentation/devicetree/bindings/bus/qcom,ssc-block-bus.yaml:30:7: [warning] wrong indentation: expected 8 but found 6 (indentation)
./Documentation/devicetree/bindings/bus/qcom,ssc-block-bus.yaml:30:22: [warning] too few spaces after comma (commas)
./Documentation/devicetree/bindings/bus/qcom,ssc-block-bus.yaml:126:111: [warning] line too long (138 > 110 characters) (line-length)

dtschema/dtc warnings/errors:
Documentation/devicetree/bindings/bus/qcom,ssc-block-bus.example.dt.yaml:0:0: /example-0/soc/bus@10ac008/pinctrl@5e10000: failed to match any schema with compatible: ['qcom,msm8998-ssc-tlmm-pinctrl']

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/patch/1583436

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.


^ permalink raw reply

* Re: [PATCH 1/2] dt-bindings: input: Add bindings for Azoteq IQS7222A/B/C
From: Rob Herring @ 2022-01-24 16:01 UTC (permalink / raw)
  To: Jeff LaBundy; +Cc: linux-input, devicetree, robh+dt, dmitry.torokhov
In-Reply-To: <20220123194232.85288-2-jeff@labundy.com>

On Sun, 23 Jan 2022 13:42:31 -0600, Jeff LaBundy wrote:
> This patch adds bindings for the Azoteq IQS7222A/B/C family of
> capacitive touch controllers.
> 
> Signed-off-by: Jeff LaBundy <jeff@labundy.com>
> ---
>  .../devicetree/bindings/input/iqs7222.yaml    | 967 ++++++++++++++++++
>  1 file changed, 967 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/input/iqs7222.yaml
> 

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/input/iqs7222.example.dt.yaml: iqs7222a@44: '#address-cells' is a required property
	From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/input/iqs7222.yaml
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/input/iqs7222.example.dt.yaml: iqs7222a@44: '#size-cells' is a required property
	From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/input/iqs7222.yaml
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/input/iqs7222.example.dt.yaml: iqs7222a@44: 'channel-10', 'channel-11', 'channel-2', 'channel-3', 'channel-4', 'channel-5', 'channel-6', 'channel-7', 'channel-8' do not match any of the regexes: '^channel-[0-19]$', '^cycle-[0-9]$', '^gpio-[0-2]$', '^slider-[0-1]$', 'pinctrl-[0-9]+'
	From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/input/iqs7222.yaml

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/patch/1583181

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.


^ permalink raw reply

* Re: [PATCH 1/3] dt-bindings: display: add bindings for MIPI DBI compatible SPI panels
From: Rob Herring @ 2022-01-24 16:01 UTC (permalink / raw)
  To: Noralf Trønnes
  Cc: dave.stevenson, thierry.reding, dri-devel, sam, david, maxime,
	robh+dt, devicetree
In-Reply-To: <20220123172520.48741-2-noralf@tronnes.org>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 4081 bytes --]

On Sun, 23 Jan 2022 18:25:18 +0100, Noralf Trønnes wrote:
> Add binding for MIPI DBI compatible SPI panels.
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
>  .../display/panel/panel-mipi-dbi-spi.yaml     | 69 +++++++++++++++++++
>  1 file changed, 69 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/panel/panel-mipi-dbi-spi.yaml
> 

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:

dtschema/dtc warnings/errors:
schemas/display/panel/panel/panel-common.yaml: ignoring, error parsing file
make[1]: *** Deleting file 'Documentation/devicetree/bindings/display/panel/panel-mipi-dbi-spi.example.dt.yaml'
schemas/display/panel/panel/panel-common.yaml: ignoring, error parsing file
Traceback (most recent call last):
  File "/usr/local/bin/dt-validate", line 170, in <module>
    sg.check_trees(filename, testtree)
  File "/usr/local/bin/dt-validate", line 119, in check_trees
    self.check_subtree(dt, subtree, False, "/", "/", filename)
  File "/usr/local/bin/dt-validate", line 110, in check_subtree
    self.check_subtree(tree, value, disabled, name, fullname + name, filename)
  File "/usr/local/bin/dt-validate", line 110, in check_subtree
    self.check_subtree(tree, value, disabled, name, fullname + name, filename)
  File "/usr/local/bin/dt-validate", line 110, in check_subtree
    self.check_subtree(tree, value, disabled, name, fullname + name, filename)
  File "/usr/local/bin/dt-validate", line 105, in check_subtree
    self.check_node(tree, subtree, disabled, nodename, fullname, filename)
  File "/usr/local/bin/dt-validate", line 49, in check_node
    errors = sorted(dtschema.DTValidator(schema).iter_errors(node), key=lambda e: e.linecol)
  File "/usr/local/lib/python3.8/dist-packages/dtschema/lib.py", line 771, in iter_errors
    for error in super().iter_errors(instance, _schema):
  File "/usr/local/lib/python3.8/dist-packages/jsonschema/validators.py", line 229, in iter_errors
    for error in errors:
  File "/usr/local/lib/python3.8/dist-packages/jsonschema/_validators.py", line 362, in allOf
    yield from validator.descend(instance, subschema, schema_path=index)
  File "/usr/local/lib/python3.8/dist-packages/jsonschema/validators.py", line 245, in descend
    for error in self.evolve(schema=schema).iter_errors(instance):
  File "/usr/local/lib/python3.8/dist-packages/dtschema/lib.py", line 771, in iter_errors
    for error in super().iter_errors(instance, _schema):
  File "/usr/local/lib/python3.8/dist-packages/jsonschema/validators.py", line 229, in iter_errors
    for error in errors:
  File "/usr/local/lib/python3.8/dist-packages/jsonschema/_validators.py", line 298, in ref
    yield from validator.descend(instance, resolved)
  File "/usr/local/lib/python3.8/dist-packages/jsonschema/validators.py", line 245, in descend
    for error in self.evolve(schema=schema).iter_errors(instance):
  File "/usr/local/lib/python3.8/dist-packages/dtschema/lib.py", line 771, in iter_errors
    for error in super().iter_errors(instance, _schema):
  File "/usr/local/lib/python3.8/dist-packages/jsonschema/validators.py", line 219, in iter_errors
    scope = id_of(_schema)
  File "/usr/local/lib/python3.8/dist-packages/jsonschema/validators.py", line 96, in _id_of
    return schema.get("$id", "")
AttributeError: 'NoneType' object has no attribute 'get'
make[1]: *** [scripts/Makefile.lib:378: Documentation/devicetree/bindings/display/panel/panel-mipi-dbi-spi.example.dt.yaml] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:1398: dt_binding_check] Error 2

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/patch/1583159

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.


^ permalink raw reply

* [PATCH 1/1] ARM: dts: stm32: fix AV96 board SAI2 pin muxing on stm32mp15
From: Olivier Moysan @ 2022-01-24 15:35 UTC (permalink / raw)
  To: Alexandre Torgue, Marek Vasut, Maxime Coquelin, Olivier Moysan,
	Rob Herring
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-stm32

Replace sai2a-2 node name by sai2a-sleep-2, to avoid name
duplication.

Fixes: 1a9a9d226f0f ("ARM: dts: stm32: fix AV96 board SAI2 pin muxing on stm32mp15")

Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com>
---
 arch/arm/boot/dts/stm32mp15-pinctrl.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
index 3b65130affec..6161f5906ec1 100644
--- a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi
@@ -1190,7 +1190,7 @@
 		};
 	};
 
-	sai2a_sleep_pins_c: sai2a-2 {
+	sai2a_sleep_pins_c: sai2a-sleep-2 {
 		pins {
 			pinmux = <STM32_PINMUX('D', 13, ANALOG)>, /* SAI2_SCK_A */
 				 <STM32_PINMUX('D', 11, ANALOG)>, /* SAI2_SD_A */
-- 
2.17.1


^ permalink raw reply related

* Re: [RFC PATCH v2 4/7] media: bcm2835-unicam: Add support for for CCP2/CSI2 camera interface
From: Dave Stevenson @ 2022-01-24 15:35 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Jean-Michel Hautbois, devicetree, kernel-list, linux-arm-kernel,
	LKML, Linux Media Mailing List, linux-rpi-kernel, lukasz,
	Mauro Carvalho Chehab, Naushir Patuck, robh, Tomi Valkeinen
In-Reply-To: <YeySvkxEfpzTj+pC@pendragon.ideasonboard.com>

Hi Laurent and Jean-Michel

On Sat, 22 Jan 2022 at 23:27, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Jean-Michel,
>
> Thank you for the patch.
>
> Dave, Naush, there are a few questions for you below.
>
> On Fri, Jan 21, 2022 at 09:18:07AM +0100, Jean-Michel Hautbois wrote:
> > Add driver for the Unicam camera receiver block on BCM283x processors.
> > It is represented as two video device nodes: unicam-image and
> > unicam-embedded which are connected to an internal subdev (named
> > unicam-subdev) in order to manage streams routing.
> >
> > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> > Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>
> >
> > ---
> > in v2: Remove the unicam_{info,debug,error} macros and use
> > dev_dbg/dev_err instead.
> > ---
> >  MAINTAINERS                                   |    1 +
> >  drivers/media/platform/Kconfig                |    1 +
> >  drivers/media/platform/Makefile               |    2 +
> >  drivers/media/platform/bcm2835/Kconfig        |   21 +
> >  drivers/media/platform/bcm2835/Makefile       |    3 +
> >  .../media/platform/bcm2835/bcm2835-unicam.c   | 2678 +++++++++++++++++
> >  .../media/platform/bcm2835/vc4-regs-unicam.h  |  253 ++
> >  7 files changed, 2959 insertions(+)
> >  create mode 100644 drivers/media/platform/bcm2835/Kconfig
> >  create mode 100644 drivers/media/platform/bcm2835/Makefile
> >  create mode 100644 drivers/media/platform/bcm2835/bcm2835-unicam.c
> >  create mode 100644 drivers/media/platform/bcm2835/vc4-regs-unicam.h
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 07f238fd5ff9..b17bb533e007 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -3684,6 +3684,7 @@ M:      Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
> >  L:   linux-media@vger.kernel.org
> >  S:   Maintained
> >  F:   Documentation/devicetree/bindings/media/brcm,bcm2835-unicam.yaml
> > +F:   drivers/media/platform/bcm2835/
> >
> >  BROADCOM BCM47XX MIPS ARCHITECTURE
> >  M:   Hauke Mehrtens <hauke@hauke-m.de>
> > diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
> > index 9fbdba0fd1e7..033b0358fbb8 100644
> > --- a/drivers/media/platform/Kconfig
> > +++ b/drivers/media/platform/Kconfig
> > @@ -170,6 +170,7 @@ source "drivers/media/platform/am437x/Kconfig"
> >  source "drivers/media/platform/xilinx/Kconfig"
> >  source "drivers/media/platform/rcar-vin/Kconfig"
> >  source "drivers/media/platform/atmel/Kconfig"
> > +source "drivers/media/platform/bcm2835/Kconfig"
> >  source "drivers/media/platform/sunxi/Kconfig"
> >
> >  config VIDEO_TI_CAL
> > diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
> > index 19bcbced7382..689e64857db1 100644
> > --- a/drivers/media/platform/Makefile
> > +++ b/drivers/media/platform/Makefile
> > @@ -85,6 +85,8 @@ obj-$(CONFIG_VIDEO_QCOM_CAMSS)              += qcom/camss/
> >
> >  obj-$(CONFIG_VIDEO_QCOM_VENUS)               += qcom/venus/
> >
> > +obj-y                                        += bcm2835/
>
> One day it would be nice to clean the media Kconfig and Makefile
> infrastructure to use a consistent style for all drivers. One can always
> dream :-)
>
> > +
> >  obj-y                                        += sunxi/
> >
> >  obj-$(CONFIG_VIDEO_MESON_GE2D)               += meson/ge2d/
> > diff --git a/drivers/media/platform/bcm2835/Kconfig b/drivers/media/platform/bcm2835/Kconfig
> > new file mode 100644
> > index 000000000000..bd1370199650
> > --- /dev/null
> > +++ b/drivers/media/platform/bcm2835/Kconfig
> > @@ -0,0 +1,21 @@
> > +# Broadcom VideoCore4 V4L2 camera support
> > +
> > +config VIDEO_BCM2835_UNICAM
> > +     tristate "Broadcom BCM283x/BCM271x Unicam video capture driver"
> > +     depends on VIDEO_V4L2
> > +     depends on ARCH_BCM2835 || COMPILE_TEST
>
> I would put the arch dependency first, but that may be just me.
>
> > +     select VIDEO_V4L2_SUBDEV_API
> > +     select MEDIA_CONTROLLER
> > +     select VIDEOBUF2_DMA_CONTIG
> > +     select V4L2_FWNODE
>
> And sort there alphabetically.
>
> > +     help
> > +       Say Y here to enable support for the BCM283x/BCM271x CSI-2 receiver.
> > +       This is a V4L2 driver that controls the CSI-2 receiver directly,
> > +       independently from the VC4 firmware.
> > +       This driver is mutually exclusive with the use of bcm2835-camera. The
> > +       firmware will disable all access to the peripheral from within the
> > +       firmware if it finds a DT node using it, and bcm2835-camera will
> > +       therefore fail to probe.
>
> Dave, Naush, what should we do with the bcm2835-camera driver in staging
> ? Do we need to keep it to support older Pi models ?

The legacy camera stack is still there and people use it. Once
libcamera has really been adopted and works with all use cases, then
possibly look at dropping it.
The MMAL interface is still needed for ISP access, so it's a minimal saving.

> > +
> > +       To compile this driver as a module, choose M here. The module will be
> > +       called bcm2835-unicam.
> > diff --git a/drivers/media/platform/bcm2835/Makefile b/drivers/media/platform/bcm2835/Makefile
> > new file mode 100644
> > index 000000000000..a98aba03598a
> > --- /dev/null
> > +++ b/drivers/media/platform/bcm2835/Makefile
> > @@ -0,0 +1,3 @@
> > +# Makefile for BCM2835 Unicam driver
> > +
> > +obj-$(CONFIG_VIDEO_BCM2835_UNICAM) += bcm2835-unicam.o
> > diff --git a/drivers/media/platform/bcm2835/bcm2835-unicam.c b/drivers/media/platform/bcm2835/bcm2835-unicam.c
> > new file mode 100644
> > index 000000000000..7636496be00a
> > --- /dev/null
> > +++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
> > @@ -0,0 +1,2678 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * BCM283x / BCM271x Unicam Capture Driver
> > + *
> > + * Copyright (C) 2017-2020 - Raspberry Pi (Trading) Ltd.
> > + *
> > + * Dave Stevenson <dave.stevenson@raspberrypi.com>
> > + *
> > + * Based on TI am437x driver by
> > + *   Benoit Parrot <bparrot@ti.com>
> > + *   Lad, Prabhakar <prabhakar.csengg@gmail.com>
> > + *
> > + * and TI CAL camera interface driver by
> > + *    Benoit Parrot <bparrot@ti.com>
> > + *
> > + *
> > + * There are two camera drivers in the kernel for BCM283x - this one
> > + * and bcm2835-camera (currently in staging).
> > + *
> > + * This driver directly controls the Unicam peripheral - there is no
> > + * involvement with the VideoCore firmware. Unicam receives CSI-2 or
> > + * CCP2 data and writes it into SDRAM.
> > + * The only potential processing options are to repack Bayer data into an
> > + * alternate format, and applying windowing.
> > + * The repacking does not shift the data, so can repack V4L2_PIX_FMT_Sxxxx10P
> > + * to V4L2_PIX_FMT_Sxxxx10, or V4L2_PIX_FMT_Sxxxx12P to V4L2_PIX_FMT_Sxxxx12,
> > + * but not generically up to V4L2_PIX_FMT_Sxxxx16. The driver will add both
> > + * formats where the relevant formats are defined, and will automatically
> > + * configure the repacking as required.
> > + * Support for windowing may be added later.
> > + *
> > + * It should be possible to connect this driver to any sensor with a
> > + * suitable output interface and V4L2 subdevice driver.
> > + *
> > + * bcm2835-camera uses the VideoCore firmware to control the sensor,
> > + * Unicam, ISP, and all tuner control loops. Fully processed frames are
> > + * delivered to the driver by the firmware. It only has sensor drivers
> > + * for Omnivision OV5647, and Sony IMX219 sensors.
> > + *
> > + * The two drivers are mutually exclusive for the same Unicam instance.
> > + * The VideoCore firmware checks the device tree configuration during boot.
> > + * If it finds device tree nodes called csi0 or csi1 it will block the
> > + * firmware from accessing the peripheral, and bcm2835-camera will
> > + * not be able to stream data.
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/delay.h>
> > +#include <linux/device.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/err.h>
> > +#include <linux/init.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/io.h>
> > +#include <linux/module.h>
> > +#include <linux/of_device.h>
> > +#include <linux/of_graph.h>
> > +#include <linux/pinctrl/consumer.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/slab.h>
> > +#include <linux/uaccess.h>
> > +#include <linux/videodev2.h>
> > +
> > +#include <media/v4l2-common.h>
> > +#include <media/v4l2-ctrls.h>
> > +#include <media/v4l2-dev.h>
> > +#include <media/v4l2-device.h>
> > +#include <media/v4l2-dv-timings.h>
> > +#include <media/v4l2-event.h>
> > +#include <media/v4l2-ioctl.h>
> > +#include <media/v4l2-fwnode.h>
> > +#include <media/videobuf2-dma-contig.h>
> > +
> > +#include <media/v4l2-async.h>
> > +#define v4l2_async_nf_add_subdev __v4l2_async_nf_add_subdev
>
> Don't do that ! It's the kind of pattern that a malicious actor would
> use to obfuscate code and get vulnerabilities merged.
>
> > +
> > +#include "vc4-regs-unicam.h"
> > +
> > +#define UNICAM_MODULE_NAME   "unicam"
> > +#define UNICAM_VERSION               "0.1.0"
>
> I doubt the version would ever be incremented, so let's just drop it.
>
> > +
> > +static int debug;
> > +module_param(debug, int, 0644);
> > +MODULE_PARM_DESC(debug, "Debug level 0-3");
>
> Not used.
>
> > +
> > +/*
> > + * Unicam must request a minimum of 250Mhz from the VPU clock.
> > + * Otherwise the input FIFOs overrun and cause image corruption.
> > + */
> > +#define MIN_VPU_CLOCK_RATE (250 * 1000 * 1000)
> > +/*
> > + * To protect against a dodgy sensor driver never returning an error from
> > + * enum_mbus_code, set a maximum index value to be used.
> > + */
> > +#define MAX_ENUM_MBUS_CODE   128
> > +
> > +/*
> > + * Stride is a 16 bit register, but also has to be a multiple of 32.
> > + */
> > +#define BPL_ALIGNMENT                32
> > +#define MAX_BYTESPERLINE     ((1 << 16) - BPL_ALIGNMENT)
> > +/*
> > + * Max width is therefore determined by the max stride divided by
> > + * the number of bits per pixel. Take 32bpp as a
> > + * worst case.
> > + * No imposed limit on the height, so adopt a square image for want
> > + * of anything better.
> > + */
> > +#define MAX_WIDTH            (MAX_BYTESPERLINE / 4)
> > +#define MAX_HEIGHT           MAX_WIDTH
> > +/* Define a nominal minimum image size */
> > +#define MIN_WIDTH            16
> > +#define MIN_HEIGHT           16
> > +/* Default size of the embedded buffer */
> > +#define UNICAM_EMBEDDED_SIZE 16384
> > +
> > +/*
> > + * Size of the dummy buffer. Can be any size really, but the DMA
> > + * allocation works in units of page sizes.
> > + */
> > +#define DUMMY_BUF_SIZE               (PAGE_SIZE)
>
> No need for parentheses.
>
> Some of those macros have toogeneric names and may result in namespace
> clashes. Please prefix them all with UNICAM_.
>
> > +
> > +#define UNICAM_SD_PAD_SINK           0
> > +#define UNICAM_SD_PAD_FIRST_SOURCE   1
>
> I'd name the source pads explicitly.
>
> #define UNICAM_SD_PAD_SOURCE_IMAGE      1
> #define UNICAM_SD_PAD_SOURCE_METADATA   2
>
> (or META instead of METADATA, up to you, as long as we use consistent
> naming through the driver).
>
> > +#define UNICAM_SD_NUM_SOURCE_PADS    2
> > +#define UNICAM_SD_NUM_PADS           (1 + UNICAM_SD_NUM_SOURCE_PADS)
> > +
> > +static inline bool unicam_sd_pad_is_sink(u32 pad)
> > +{
> > +     /* Camera RX has 1 sink pad, and N source pads */
> > +     return pad == 0;
> > +}
> > +
> > +static inline bool unicam_sd_pad_is_source(u32 pad)
> > +{
> > +     /* Camera RX has 1 sink pad, and N source pads */
> > +     return pad >= UNICAM_SD_PAD_FIRST_SOURCE &&
> > +            pad <= UNICAM_SD_NUM_SOURCE_PADS;
>
>         return pad != UNICAM_SD_PAD_SINK;
>
> and drop UNICAM_SD_PAD_FIRST_SOURCE and UNICAM_SD_NUM_SOURCE_PADS.
>
> > +}
> > +
> > +enum node_types {
>
> enum unicam_node_type {
>
> > +     IMAGE_NODE,
> > +     METADATA_NODE,
> > +     MAX_NODES
> > +};
>
> UNICAM_ prefixes please.
>
> > +
> > +#define MASK_CS_DEFAULT              BIT(V4L2_COLORSPACE_DEFAULT)
>
> This and several of the macros below are not used.
>
> > +#define MASK_CS_SMPTE170M    BIT(V4L2_COLORSPACE_SMPTE170M)
> > +#define MASK_CS_SMPTE240M    BIT(V4L2_COLORSPACE_SMPTE240M)
> > +#define MASK_CS_REC709               BIT(V4L2_COLORSPACE_REC709)
> > +#define MASK_CS_BT878                BIT(V4L2_COLORSPACE_BT878)
> > +#define MASK_CS_470_M                BIT(V4L2_COLORSPACE_470_SYSTEM_M)
> > +#define MASK_CS_470_BG               BIT(V4L2_COLORSPACE_470_SYSTEM_BG)
> > +#define MASK_CS_JPEG         BIT(V4L2_COLORSPACE_JPEG)
> > +#define MASK_CS_SRGB         BIT(V4L2_COLORSPACE_SRGB)
> > +#define MASK_CS_OPRGB                BIT(V4L2_COLORSPACE_OPRGB)
> > +#define MASK_CS_BT2020               BIT(V4L2_COLORSPACE_BT2020)
> > +#define MASK_CS_RAW          BIT(V4L2_COLORSPACE_RAW)
> > +#define MASK_CS_DCI_P3               BIT(V4L2_COLORSPACE_DCI_P3)
> > +
> > +#define MAX_COLORSPACE               32
> > +
> > +/*
> > + * struct unicam_fmt - Unicam media bus format information
> > + * @pixelformat: V4L2 pixel format FCC identifier. 0 if n/a.
> > + * @repacked_fourcc: V4L2 pixel format FCC identifier if the data is expanded
> > + * out to 16bpp. 0 if n/a.
> > + * @code: V4L2 media bus format code.
> > + * @depth: Bits per pixel as delivered from the source.
> > + * @csi_dt: CSI data type.
> > + * @valid_colorspaces: Bitmask of valid colorspaces so that the Media Controller
> > + *           centric try_fmt can validate the colorspace and pass
> > + *           v4l2-compliance.
>
> I'd actually drop colorspace support completely. Unicam doesn't affect
> the colorspace. It will output whatever it receives from the sensor. You
> can accept any colorspace on the sink pad of the subdev, and just
> propagate that to the source pad.
>
> If that causes v4l2-compliance failures, then we have a problem either
> in the sensor drivers, or in v4l2-compliance.
>
> > + * @check_variants: Flag to denote that there are multiple mediabus formats
> > + *           still in the list that could match this V4L2 format.
> > + * @mc_skip: Media Controller shouldn't list this format via ENUM_FMT as it is
> > + *           a duplicate of an earlier format.
> > + * @metadata_fmt: This format only applies to the metadata pad.
> > + */
> > +struct unicam_fmt {
> > +     u32     fourcc;
> > +     u32     repacked_fourcc;
> > +     u32     code;
> > +     u8      depth;
> > +     u8      csi_dt;
> > +     u32     valid_colorspaces;
> > +     u8      check_variants:1;
> > +     u8      mc_skip:1;
> > +     u8      metadata_fmt:1;
> > +};
> > +
> > +static const struct unicam_fmt formats[] = {
> > +     /* YUV Formats */
> > +     {
> > +             .fourcc         = V4L2_PIX_FMT_YUYV,
> > +             .code           = MEDIA_BUS_FMT_YUYV8_2X8,
>
> The convention for CSI-2 buses is to used the _1X16 media bus codes for
> YUV. You can drop the first four entries, and drop the check_variants
> and mc_skip fields.

In which case you need a fix for adv7180 which only advertises
MEDIA_BUS_FMT_UYVY8_2X8 despite having CSI2 output variants.

> > +             .depth          = 16,
> > +             .csi_dt         = 0x1e,
> > +             .check_variants = 1,
> > +             .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 |
> > +                                  MASK_CS_JPEG,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_UYVY,
> > +             .code           = MEDIA_BUS_FMT_UYVY8_2X8,
> > +             .depth          = 16,
> > +             .csi_dt         = 0x1e,
> > +             .check_variants = 1,
> > +             .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 |
> > +                                  MASK_CS_JPEG,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_YVYU,
> > +             .code           = MEDIA_BUS_FMT_YVYU8_2X8,
> > +             .depth          = 16,
> > +             .csi_dt         = 0x1e,
> > +             .check_variants = 1,
> > +             .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 |
> > +                                  MASK_CS_JPEG,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_VYUY,
> > +             .code           = MEDIA_BUS_FMT_VYUY8_2X8,
> > +             .depth          = 16,
> > +             .csi_dt         = 0x1e,
> > +             .check_variants = 1,
> > +             .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 |
> > +                                  MASK_CS_JPEG,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_YUYV,
> > +             .code           = MEDIA_BUS_FMT_YUYV8_1X16,
> > +             .depth          = 16,
> > +             .csi_dt         = 0x1e,
> > +             .mc_skip        = 1,
> > +             .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 |
> > +                                  MASK_CS_JPEG,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_UYVY,
> > +             .code           = MEDIA_BUS_FMT_UYVY8_1X16,
> > +             .depth          = 16,
> > +             .csi_dt         = 0x1e,
> > +             .mc_skip        = 1,
> > +             .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 |
> > +                                  MASK_CS_JPEG,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_YVYU,
> > +             .code           = MEDIA_BUS_FMT_YVYU8_1X16,
> > +             .depth          = 16,
> > +             .csi_dt         = 0x1e,
> > +             .mc_skip        = 1,
> > +             .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 |
> > +                                  MASK_CS_JPEG,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_VYUY,
> > +             .code           = MEDIA_BUS_FMT_VYUY8_1X16,
> > +             .depth          = 16,
> > +             .csi_dt         = 0x1e,
> > +             .mc_skip        = 1,
> > +             .valid_colorspaces = MASK_CS_SMPTE170M | MASK_CS_REC709 |
> > +                                  MASK_CS_JPEG,
> > +     }, {
> > +     /* RGB Formats */
> > +             .fourcc         = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
> > +             .code           = MEDIA_BUS_FMT_RGB565_2X8_LE,
> > +             .depth          = 16,
> > +             .csi_dt         = 0x22,
> > +             .valid_colorspaces = MASK_CS_SRGB,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
> > +             .code           = MEDIA_BUS_FMT_RGB565_2X8_BE,
> > +             .depth          = 16,
> > +             .csi_dt         = 0x22,
> > +             .valid_colorspaces = MASK_CS_SRGB,
>
> CSI-2 specifies the RGB565 format unambiguously, there are no little
> endian of big endian variants. Let's drop one of the two entries, and
> use MEDIA_BUS_FMT_RGB565_1X15. Dave, Naush, what is the correct pixel
> format for this, is data layed out in big endian or little endian ?

There's no remapping, so it's written to memory in the order the bytes come in.

> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
> > +             .code           = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
> > +             .depth          = 16,
> > +             .csi_dt         = 0x21,
> > +             .valid_colorspaces = MASK_CS_SRGB,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
> > +             .code           = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE,
> > +             .depth          = 16,
> > +             .csi_dt         = 0x21,
> > +             .valid_colorspaces = MASK_CS_SRGB,
>
> Same here, but we need to define a new MEDIA_BUS_FMT_RGB555_1X16 format.
> The CSI-2 RGB555 data type has the padding bit between the green and
> blue components, so I wonder if Unicam maps that to one of
> V4L2_PIX_FMT_RGB555 or V4L2_PIX_FMT_RGB555X, or if a new pixel format is
> needed too.
>
> Another option would be to drop RGB555 support until someone needs it
> (with a comment in the table to tell the entry is missing).

What an odd place to put the padding - I'd never noticed that before.

Again no remapping, so it would need a new format. Happy to drop it.

> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_RGB24, /* rgb */
> > +             .code           = MEDIA_BUS_FMT_RGB888_1X24,
> > +             .depth          = 24,
> > +             .csi_dt         = 0x24,
> > +             .valid_colorspaces = MASK_CS_SRGB,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_BGR24, /* bgr */
> > +             .code           = MEDIA_BUS_FMT_BGR888_1X24,
> > +             .depth          = 24,
> > +             .csi_dt         = 0x24,
> > +             .valid_colorspaces = MASK_CS_SRGB,
>
> This is possibly more tricky, as CSI-2 defined RGB888 as being
> transmitted in BGR order, but sensors could possibly also support RGB as
> a non-standard extension (the same may CSI-2 standardizes on UYVY, but
> many sensors can swap components). We can keep both entry I suppose.
>
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_RGB32, /* argb */
> > +             .code           = MEDIA_BUS_FMT_ARGB8888_1X32,
> > +             .depth          = 32,
> > +             .csi_dt         = 0x0,
> > +             .valid_colorspaces = MASK_CS_SRGB,
>
> There's no 32-bit RGB in CSI-2, should this be dropped ?

Yes, drop it. I'm not sure why it got added in the first place as it
doesn't have a data type defined.

> > +     }, {
> > +     /* Bayer Formats */
> > +             .fourcc         = V4L2_PIX_FMT_SBGGR8,
> > +             .code           = MEDIA_BUS_FMT_SBGGR8_1X8,
> > +             .depth          = 8,
> > +             .csi_dt         = 0x2a,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_SGBRG8,
> > +             .code           = MEDIA_BUS_FMT_SGBRG8_1X8,
> > +             .depth          = 8,
> > +             .csi_dt         = 0x2a,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_SGRBG8,
> > +             .code           = MEDIA_BUS_FMT_SGRBG8_1X8,
> > +             .depth          = 8,
> > +             .csi_dt         = 0x2a,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_SRGGB8,
> > +             .code           = MEDIA_BUS_FMT_SRGGB8_1X8,
> > +             .depth          = 8,
> > +             .csi_dt         = 0x2a,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_SBGGR10P,
> > +             .repacked_fourcc = V4L2_PIX_FMT_SBGGR10,
> > +             .code           = MEDIA_BUS_FMT_SBGGR10_1X10,
> > +             .depth          = 10,
> > +             .csi_dt         = 0x2b,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_SGBRG10P,
> > +             .repacked_fourcc = V4L2_PIX_FMT_SGBRG10,
> > +             .code           = MEDIA_BUS_FMT_SGBRG10_1X10,
> > +             .depth          = 10,
> > +             .csi_dt         = 0x2b,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_SGRBG10P,
> > +             .repacked_fourcc = V4L2_PIX_FMT_SGRBG10,
> > +             .code           = MEDIA_BUS_FMT_SGRBG10_1X10,
> > +             .depth          = 10,
> > +             .csi_dt         = 0x2b,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_SRGGB10P,
> > +             .repacked_fourcc = V4L2_PIX_FMT_SRGGB10,
> > +             .code           = MEDIA_BUS_FMT_SRGGB10_1X10,
> > +             .depth          = 10,
> > +             .csi_dt         = 0x2b,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_SBGGR12P,
> > +             .repacked_fourcc = V4L2_PIX_FMT_SBGGR12,
> > +             .code           = MEDIA_BUS_FMT_SBGGR12_1X12,
> > +             .depth          = 12,
> > +             .csi_dt         = 0x2c,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_SGBRG12P,
> > +             .repacked_fourcc = V4L2_PIX_FMT_SGBRG12,
> > +             .code           = MEDIA_BUS_FMT_SGBRG12_1X12,
> > +             .depth          = 12,
> > +             .csi_dt         = 0x2c,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_SGRBG12P,
> > +             .repacked_fourcc = V4L2_PIX_FMT_SGRBG12,
> > +             .code           = MEDIA_BUS_FMT_SGRBG12_1X12,
> > +             .depth          = 12,
> > +             .csi_dt         = 0x2c,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_SRGGB12P,
> > +             .repacked_fourcc = V4L2_PIX_FMT_SRGGB12,
> > +             .code           = MEDIA_BUS_FMT_SRGGB12_1X12,
> > +             .depth          = 12,
> > +             .csi_dt         = 0x2c,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_SBGGR14P,
> > +             .repacked_fourcc = V4L2_PIX_FMT_SBGGR14,
> > +             .code           = MEDIA_BUS_FMT_SBGGR14_1X14,
> > +             .depth          = 14,
> > +             .csi_dt         = 0x2d,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_SGBRG14P,
> > +             .repacked_fourcc = V4L2_PIX_FMT_SGBRG14,
> > +             .code           = MEDIA_BUS_FMT_SGBRG14_1X14,
> > +             .depth          = 14,
> > +             .csi_dt         = 0x2d,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_SGRBG14P,
> > +             .repacked_fourcc = V4L2_PIX_FMT_SGRBG14,
> > +             .code           = MEDIA_BUS_FMT_SGRBG14_1X14,
> > +             .depth          = 14,
> > +             .csi_dt         = 0x2d,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_SRGGB14P,
> > +             .repacked_fourcc = V4L2_PIX_FMT_SRGGB14,
> > +             .code           = MEDIA_BUS_FMT_SRGGB14_1X14,
> > +             .depth          = 14,
> > +             .csi_dt         = 0x2d,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +     /*
> > +      * 16 bit Bayer formats could be supported, but there is no CSI2
> > +      * data_type defined for raw 16, and no sensors that produce it at
> > +      * present.
> > +      */
>
> RAW16 is now defined in CSI-2, but that can be handled later.
>
> > +
> > +     /* Greyscale formats */
> > +             .fourcc         = V4L2_PIX_FMT_GREY,
> > +             .code           = MEDIA_BUS_FMT_Y8_1X8,
> > +             .depth          = 8,
> > +             .csi_dt         = 0x2a,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_Y10P,
> > +             .repacked_fourcc = V4L2_PIX_FMT_Y10,
> > +             .code           = MEDIA_BUS_FMT_Y10_1X10,
> > +             .depth          = 10,
> > +             .csi_dt         = 0x2b,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_Y12P,
> > +             .repacked_fourcc = V4L2_PIX_FMT_Y12,
> > +             .code           = MEDIA_BUS_FMT_Y12_1X12,
> > +             .depth          = 12,
> > +             .csi_dt         = 0x2c,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     }, {
> > +             .fourcc         = V4L2_PIX_FMT_Y14P,
> > +             .repacked_fourcc = V4L2_PIX_FMT_Y14,
> > +             .code           = MEDIA_BUS_FMT_Y14_1X14,
> > +             .depth          = 14,
> > +             .csi_dt         = 0x2d,
> > +             .valid_colorspaces = MASK_CS_RAW,
> > +     },
> > +     /* Embedded data format */
> > +     {
> > +             .fourcc         = V4L2_META_FMT_8,
> > +             .code           = MEDIA_BUS_FMT_METADATA_8,
> > +             .depth          = 8,
> > +             .metadata_fmt   = 1,
> > +     }
> > +};
>
> Let's reorder the code a bit to improve readability:
>
> - Macro definitions
> - Structure definitions (with the container_of wrappers following the
>   respective structure)
> - Misc helper functions (from is_metadata_node() to reg_write_field())
> - Format data table and helper functions (from find_format_by_code() to
>   unicam_calc_format_size_bpl())
> - Hardware handling:
>   - From unicam_wr_dma_addr() to unicam_isr()
>   - From unicam_set_packing_config() to unicam_disable()
> - V4L2 subdev (ops & initialization & registration)
> - vb2 queue opq
> - V4L2 video device (ops & initialization & registration)
> - Probe
>
> I recommend adding a comment header in front of each section after the
> structure definitions with a distinctive visual appearance, to delimit
> code blocks very clearly. I usually use the following style:
>
> /* -----------------------------------------------------------------------------
>  * V4L2 Subdev Operations
>  */
>
> > +
> > +struct unicam_buffer {
> > +     struct vb2_v4l2_buffer vb;
> > +     struct list_head list;
> > +};
> > +
> > +static inline struct unicam_buffer *to_unicam_buffer(struct vb2_buffer *vb)
> > +{
> > +     return container_of(vb, struct unicam_buffer, vb.vb2_buf);
> > +}
> > +
> > +struct unicam_node {
> > +     bool registered;
> > +     int open;
>
> Not used. Please go through all structure fields and delete the ones
> that are not used.
>
> > +     bool streaming;
> > +     unsigned int node_id;
> > +     /* Source pad id on the sensor for this node */
> > +     unsigned int src_pad_id;
> > +     /* Pointer pointing to current v4l2_buffer */
> > +     struct unicam_buffer *cur_frm;
> > +     /* Pointer pointing to next v4l2_buffer */
> > +     struct unicam_buffer *next_frm;
> > +     /* video capture */
> > +     const struct unicam_fmt *fmt;
> > +     /* Used to store current pixel format */
> > +     struct v4l2_format v_fmt;
> > +     /* Used to store current mbus frame format */
> > +     struct v4l2_mbus_framefmt m_fmt;
> > +     /* Buffer queue used in video-buf */
> > +     struct vb2_queue buffer_queue;
> > +     /* Queue of filled frames */
> > +     struct list_head dma_queue;
> > +     /* IRQ lock for DMA queue */
> > +     spinlock_t dma_queue_lock;
> > +     /* lock used to access this structure */
> > +     struct mutex lock;
> > +     /* Identifies video device for this channel */
> > +     struct video_device video_dev;
> > +     /* Pointer to the parent handle */
> > +     struct unicam_device *dev;
> > +     struct media_pad pad;
> > +     unsigned int embedded_lines;
> > +     struct media_pipeline pipe;
> > +     /*
> > +      * Dummy buffer intended to be used by unicam
> > +      * if we have no other queued buffers to swap to.
> > +      */
> > +     void *dummy_buf_cpu_addr;
> > +     dma_addr_t dummy_buf_dma_addr;
> > +};
> > +
> > +struct unicam_device {
> > +     struct kref kref;
> > +
> > +     /* V4l2 specific parameters */
> > +     struct v4l2_async_subdev asd;
> > +
> > +     /* peripheral base address */
> > +     void __iomem *base;
> > +     /* clock gating base address */
> > +     void __iomem *clk_gate_base;
> > +     /* lp clock handle */
> > +     struct clk *clock;
> > +     /* vpu clock handle */
> > +     struct clk *vpu_clock;
> > +     /* vpu clock request */
> > +     struct clk_request *vpu_req;
>
> Not used (and that may be a problem).
>
> > +     /* clock status for error handling */
> > +     bool clocks_enabled;
> > +     /* V4l2 device */
> > +     struct v4l2_device v4l2_dev;
> > +     struct media_device mdev;
> > +
> > +     /* parent device */
> > +     struct platform_device *pdev;
>
> The pdev field is only used to access pdev.dev, so I'd replace it with
> the struct device.
>
> > +     /* subdevice async Notifier */
> > +     struct v4l2_async_notifier notifier;
> > +     unsigned int sequence;
> > +
> > +     /* ptr to  sub device */
> > +     struct v4l2_subdev *sensor;
> > +     /* Pad config for the sensor */
> > +     struct v4l2_subdev_state *sensor_state;
> > +
> > +     /* Internal subdev */
> > +     struct v4l2_subdev sd;
> > +     struct media_pad pads[UNICAM_SD_NUM_PADS];
> > +
> > +     bool streaming;
>
> "streaming" is ambiguous, it's not clear it relates to the subdev. I'd
> group all the fields related to the subdev in a structure:
>
>         struct {
>                 struct v4l2_subdev sd;
>                 struct media_pad pads[UNICAM_SD_NUM_PADS];
>                 bool streaming;
>         } subdev;
>
> (there may be more, I haven't checked)
>
> > +
> > +     enum v4l2_mbus_type bus_type;
> > +     /*
> > +      * Stores bus.mipi_csi2.flags for CSI2 sensors, or
> > +      * bus.mipi_csi1.strobe for CCP2.
> > +      */
> > +     unsigned int bus_flags;
> > +     unsigned int max_data_lanes;
> > +     unsigned int active_data_lanes;
> > +     bool sensor_embedded_data;
> > +
> > +     struct unicam_node node[MAX_NODES];
> > +     struct v4l2_ctrl_handler ctrl_handler;
> > +
> > +     bool mc_api;
> > +};
> > +
> > +static inline struct unicam_device *
> > +to_unicam_device(struct v4l2_device *v4l2_dev)
>
> I'd rename this to v4l2_device_to_unicam_device(), as there's another
> container_of wrapper.
>
> > +{
> > +     return container_of(v4l2_dev, struct unicam_device, v4l2_dev);
> > +}
> > +
> > +static inline struct unicam_device *
> > +sd_to_unicam_device(struct v4l2_subdev *sd)
> > +{
> > +     return container_of(sd, struct unicam_device, sd);
> > +}
> > +
> > +static inline bool is_metadata_node(struct unicam_node *node)
> > +{
> > +     return node->video_dev.device_caps & V4L2_CAP_META_CAPTURE;
> > +}
> > +
> > +static inline bool is_image_node(struct unicam_node *node)
> > +{
> > +     return node->video_dev.device_caps & V4L2_CAP_VIDEO_CAPTURE;
> > +}
> > +
> > +/* Hardware access */
> > +static inline void clk_write(struct unicam_device *dev, u32 val)
> > +{
> > +     writel(val | 0x5a000000, dev->clk_gate_base);
> > +}
>
> The name of this function and the functions below are too generic. Add a
> unicam_ prefix.
>
> > +
> > +static inline u32 reg_read(struct unicam_device *dev, u32 offset)
> > +{
> > +     return readl(dev->base + offset);
> > +}
> > +
> > +static inline void reg_write(struct unicam_device *dev, u32 offset, u32 val)
> > +{
> > +     writel(val, dev->base + offset);
> > +}
> > +
> > +static inline int get_field(u32 value, u32 mask)
> > +{
> > +     return (value & mask) >> __ffs(mask);
> > +}
> > +
> > +static inline void set_field(u32 *valp, u32 field, u32 mask)
> > +{
> > +     u32 val = *valp;
> > +
> > +     val &= ~mask;
> > +     val |= (field << __ffs(mask)) & mask;
> > +     *valp = val;
> > +}
> > +
> > +static inline u32 reg_read_field(struct unicam_device *dev, u32 offset,
> > +                              u32 mask)
>
> Not used.
>
> > +{
> > +     return get_field(reg_read(dev, offset), mask);
> > +}
> > +
> > +static inline void reg_write_field(struct unicam_device *dev, u32 offset,
> > +                                u32 field, u32 mask)
> > +{
> > +     u32 val = reg_read(dev, offset);
> > +
> > +     set_field(&val, field, mask);
> > +     reg_write(dev, offset, val);
> > +}
>
> I'm really not a bit fan of the read-modify-update patterns, more often
> than not they can be replaced by direct writes. No need to fix this
> though, it's ok.
>
> > +
> > +/* Power management functions */
> > +static inline int unicam_runtime_get(struct unicam_device *dev)
> > +{
> > +     return pm_runtime_get_sync(&dev->pdev->dev);
>
> Use pm_runtime_resume_and_get() instead, as the error handling is broken
> in the driver otherwise.
>
> > +}
> > +
> > +static inline void unicam_runtime_put(struct unicam_device *dev)
> > +{
> > +     pm_runtime_put_sync(&dev->pdev->dev);
> > +}
>
> Drop these wrappers and call the functions directly.
>
> > +
> > +/* Format setup functions */
> > +static const struct unicam_fmt *find_format_by_code(u32 code)
> > +{
> > +     unsigned int i;
> > +
> > +     for (i = 0; i < ARRAY_SIZE(formats); i++) {
> > +             if (formats[i].code == code)
> > +                     return &formats[i];
> > +     }
> > +
> > +     return NULL;
> > +}
> > +
> > +static const struct unicam_fmt *find_format_by_fourcc(u32 fourcc)
> > +{
> > +     unsigned int i;
> > +
> > +     for (i = 0; i < ARRAY_SIZE(formats); ++i) {
> > +             if (formats[i].fourcc == fourcc)
> > +                     return &formats[i];
> > +     }
> > +
> > +     return NULL;
> > +}
> > +
> > +static unsigned int bytes_per_line(u32 width, const struct unicam_fmt *fmt,
> > +                                u32 v4l2_fourcc)
> > +{
> > +     if (v4l2_fourcc == fmt->repacked_fourcc)
> > +             /* Repacking always goes to 16bpp */
> > +             return ALIGN(width << 1, BPL_ALIGNMENT);
> > +     else
> > +             return ALIGN((width * fmt->depth) >> 3, BPL_ALIGNMENT);
> > +}
> > +
> > +static int unicam_calc_format_size_bpl(struct unicam_device *dev,
> > +                                    const struct unicam_fmt *fmt,
> > +                                    struct v4l2_format *f)
> > +{
> > +     unsigned int min_bytesperline;
> > +
> > +     v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, MAX_WIDTH, 2,
> > +                           &f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 0,
> > +                           0);
> > +
> > +     min_bytesperline = bytes_per_line(f->fmt.pix.width, fmt,
> > +                                       f->fmt.pix.pixelformat);
> > +
> > +     if (f->fmt.pix.bytesperline > min_bytesperline &&
> > +         f->fmt.pix.bytesperline <= MAX_BYTESPERLINE)
> > +             f->fmt.pix.bytesperline = ALIGN(f->fmt.pix.bytesperline,
> > +                                             BPL_ALIGNMENT);
> > +     else
> > +             f->fmt.pix.bytesperline = min_bytesperline;
> > +
> > +     f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
> > +
> > +     dev_dbg(dev->v4l2_dev.dev, "%s: fourcc: %08X size: %dx%d bpl:%d img_size:%d\n",
> > +             __func__,
> > +             f->fmt.pix.pixelformat,
> > +             f->fmt.pix.width, f->fmt.pix.height,
> > +             f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
> > +
> > +     return 0;
> > +}
> > +
> > +static void unicam_wr_dma_addr(struct unicam_device *dev, dma_addr_t dmaaddr,
> > +                            unsigned int buffer_size, int node_id)
> > +{
> > +     dma_addr_t endaddr = dmaaddr + buffer_size;
> > +
> > +     if (node_id == IMAGE_NODE) {
> > +             reg_write(dev, UNICAM_IBSA0, dmaaddr);
> > +             reg_write(dev, UNICAM_IBEA0, endaddr);
> > +     } else {
> > +             reg_write(dev, UNICAM_DBSA0, dmaaddr);
> > +             reg_write(dev, UNICAM_DBEA0, endaddr);
> > +     }
> > +}
> > +
> > +static unsigned int unicam_get_lines_done(struct unicam_device *dev)
> > +{
> > +     dma_addr_t start_addr, cur_addr;
> > +     unsigned int stride = dev->node[IMAGE_NODE].v_fmt.fmt.pix.bytesperline;
> > +     struct unicam_buffer *frm = dev->node[IMAGE_NODE].cur_frm;
> > +
> > +     if (!frm)
> > +             return 0;
> > +
> > +     start_addr = vb2_dma_contig_plane_dma_addr(&frm->vb.vb2_buf, 0);
> > +     cur_addr = reg_read(dev, UNICAM_IBWP);
> > +     return (unsigned int)(cur_addr - start_addr) / stride;
> > +}
> > +
> > +static void unicam_schedule_next_buffer(struct unicam_node *node)
> > +{
> > +     struct unicam_device *dev = node->dev;
> > +     struct unicam_buffer *buf;
> > +     unsigned int size;
> > +     dma_addr_t addr;
> > +
> > +     buf = list_first_entry(&node->dma_queue, struct unicam_buffer, list);
> > +     node->next_frm = buf;
> > +     list_del(&buf->list);
> > +
> > +     addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
> > +     if (is_image_node(node)) {
> > +             size = node->v_fmt.fmt.pix.sizeimage;
> > +             unicam_wr_dma_addr(dev, addr, size, IMAGE_NODE);
> > +     } else {
> > +             size = node->v_fmt.fmt.meta.buffersize;
> > +             unicam_wr_dma_addr(dev, addr, size, METADATA_NODE);
> > +     }
> > +}
> > +
> > +static void unicam_schedule_dummy_buffer(struct unicam_node *node)
> > +{
> > +     struct unicam_device *dev = node->dev;
> > +     int node_id = is_image_node(node) ? IMAGE_NODE : METADATA_NODE;
> > +
> > +     dev_dbg(dev->v4l2_dev.dev, "Scheduling dummy buffer for node %d\n", node_id);
> > +
> > +     unicam_wr_dma_addr(dev, node->dummy_buf_dma_addr, DUMMY_BUF_SIZE,
> > +                        node_id);
> > +     node->next_frm = NULL;
> > +}
> > +
> > +static void unicam_process_buffer_complete(struct unicam_node *node,
> > +                                        unsigned int sequence)
> > +{
> > +     node->cur_frm->vb.field = node->m_fmt.field;
> > +     node->cur_frm->vb.sequence = sequence;
> > +
> > +     vb2_buffer_done(&node->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
> > +}
> > +
> > +static void unicam_queue_event_sof(struct unicam_device *unicam)
> > +{
> > +     struct v4l2_event event = {
> > +             .type = V4L2_EVENT_FRAME_SYNC,
> > +             .u.frame_sync.frame_sequence = unicam->sequence,
> > +     };
> > +
> > +     v4l2_event_queue(&unicam->node[IMAGE_NODE].video_dev, &event);
> > +}
> > +
> > +/*
> > + * unicam_isr : ISR handler for unicam capture
> > + * @irq: irq number
> > + * @dev_id: dev_id ptr
> > + *
> > + * It changes status of the captured buffer, takes next buffer from the queue
> > + * and sets its address in unicam registers
> > + */
> > +static irqreturn_t unicam_isr(int irq, void *dev)
> > +{
> > +     struct unicam_device *unicam = dev;
> > +     unsigned int lines_done = unicam_get_lines_done(dev);
> > +     unsigned int sequence = unicam->sequence;
> > +     unsigned int i;
> > +     u32 ista, sta;
> > +     bool fe;
> > +     u64 ts;
> > +
> > +     sta = reg_read(unicam, UNICAM_STA);
> > +     /* Write value back to clear the interrupts */
> > +     reg_write(unicam, UNICAM_STA, sta);
> > +
> > +     ista = reg_read(unicam, UNICAM_ISTA);
> > +     /* Write value back to clear the interrupts */
> > +     reg_write(unicam, UNICAM_ISTA, ista);
> > +
> > +     dev_dbg(unicam->v4l2_dev.dev, "ISR: ISTA: 0x%X, STA: 0x%X, sequence %d, lines done %d",
> > +             ista, sta, sequence, lines_done);
> > +
> > +     if (!(sta & (UNICAM_IS | UNICAM_PI0)))
> > +             return IRQ_HANDLED;
> > +
> > +     /*
> > +      * Look for either the Frame End interrupt or the Packet Capture status
> > +      * to signal a frame end.
> > +      */
> > +     fe = (ista & UNICAM_FEI || sta & UNICAM_PI0);
>
> No need for the outer parentheses.
>
> > +
> > +     /*
> > +      * We must run the frame end handler first. If we have a valid next_frm
> > +      * and we get a simultaneout FE + FS interrupt, running the FS handler
> > +      * first would null out the next_frm ptr and we would have lost the
> > +      * buffer forever.
> > +      */
> > +     if (fe) {
> > +             /*
> > +              * Ensure we have swapped buffers already as we can't
> > +              * stop the peripheral. If no buffer is available, use a
> > +              * dummy buffer to dump out frames until we get a new buffer
> > +              * to use.
> > +              */
> > +             for (i = 0; i < ARRAY_SIZE(unicam->node); i++) {
> > +                     if (!unicam->node[i].streaming)
> > +                             continue;
> > +
> > +                     /*
> > +                      * If cur_frm == next_frm, it means we have not had
> > +                      * a chance to swap buffers, likely due to having
> > +                      * multiple interrupts occurring simultaneously (like FE
> > +                      * + FS + LS). In this case, we cannot signal the buffer
> > +                      * as complete, as the HW will reuse that buffer.
> > +                      */
> > +                     if (unicam->node[i].cur_frm &&
> > +                         unicam->node[i].cur_frm != unicam->node[i].next_frm)
> > +                             unicam_process_buffer_complete(&unicam->node[i],
> > +                                                            sequence);
> > +                     unicam->node[i].cur_frm = unicam->node[i].next_frm;
> > +             }
> > +             unicam->sequence++;
> > +     }
> > +
> > +     if (ista & UNICAM_FSI) {
> > +             /*
> > +              * Timestamp is to be when the first data byte was captured,
> > +              * aka frame start.
> > +              */
> > +             ts = ktime_get_ns();
> > +             for (i = 0; i < ARRAY_SIZE(unicam->node); i++) {
> > +                     if (!unicam->node[i].streaming)
> > +                             continue;
> > +
> > +                     if (unicam->node[i].cur_frm)
> > +                             unicam->node[i].cur_frm->vb.vb2_buf.timestamp =
> > +                                                             ts;
> > +                     else
> > +                             dev_dbg(unicam->v4l2_dev.dev, "ISR: [%d] Dropping frame, buffer not available at FS\n",
> > +                                     i);
> > +                     /*
> > +                      * Set the next frame output to go to a dummy frame
> > +                      * if we have not managed to obtain another frame
> > +                      * from the queue.
> > +                      */
> > +                     unicam_schedule_dummy_buffer(&unicam->node[i]);
> > +             }
> > +
> > +             unicam_queue_event_sof(unicam);
> > +     }
> > +
> > +     /*
> > +      * Cannot swap buffer at frame end, there may be a race condition
> > +      * where the HW does not actually swap it if the new frame has
> > +      * already started.
> > +      */
> > +     if (ista & (UNICAM_FSI | UNICAM_LCI) && !fe) {
> > +             for (i = 0; i < ARRAY_SIZE(unicam->node); i++) {
> > +                     if (!unicam->node[i].streaming)
> > +                             continue;
> > +
> > +                     spin_lock(&unicam->node[i].dma_queue_lock);
> > +                     if (!list_empty(&unicam->node[i].dma_queue) &&
> > +                         !unicam->node[i].next_frm)
> > +                             unicam_schedule_next_buffer(&unicam->node[i]);
> > +                     spin_unlock(&unicam->node[i].dma_queue_lock);
> > +             }
> > +     }
> > +
> > +     if (reg_read(unicam, UNICAM_ICTL) & UNICAM_FCM) {
> > +             /* Switch out of trigger mode if selected */
> > +             reg_write_field(unicam, UNICAM_ICTL, 1, UNICAM_TFC);
> > +             reg_write_field(unicam, UNICAM_ICTL, 0, UNICAM_FCM);
> > +     }
> > +     return IRQ_HANDLED;
> > +}
> > +
> > +/* V4L2 Common IOCTLs */
> > +static int unicam_querycap(struct file *file, void *priv,
> > +                        struct v4l2_capability *cap)
> > +{
> > +     struct unicam_node *node = video_drvdata(file);
> > +     struct unicam_device *dev = node->dev;
> > +
> > +     strscpy(cap->driver, UNICAM_MODULE_NAME, sizeof(cap->driver));
> > +     strscpy(cap->card, UNICAM_MODULE_NAME, sizeof(cap->card));
> > +
> > +     snprintf(cap->bus_info, sizeof(cap->bus_info),
> > +              "platform:%s", dev_name(&dev->pdev->dev));
> > +
> > +     cap->capabilities |= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE;
> > +
> > +     return 0;
> > +}
> > +
> > +static int unicam_log_status(struct file *file, void *fh)
> > +{
> > +     struct unicam_node *node = video_drvdata(file);
> > +     struct unicam_device *dev = node->dev;
> > +     u32 reg;
> > +
> > +     /* status for sub devices */
> > +     v4l2_device_call_all(&dev->v4l2_dev, 0, core, log_status);
>
> I'm tempted to drop this, bit I won't insist.

It's more useful in the video-node centric world that you've dropped
support for. Downstream will need to maintain that support.

> > +
> > +     dev_info(dev->v4l2_dev.dev, "-----Receiver status-----\n");
> > +     dev_info(dev->v4l2_dev.dev, "V4L2 width/height:   %ux%u\n",
> > +              node->v_fmt.fmt.pix.width, node->v_fmt.fmt.pix.height);
> > +     dev_info(dev->v4l2_dev.dev, "Mediabus format:     %08x\n", node->fmt->code);
> > +     dev_info(dev->v4l2_dev.dev, "V4L2 format:         %08x\n",
> > +              node->v_fmt.fmt.pix.pixelformat);
> > +     reg = reg_read(dev, UNICAM_IPIPE);
> > +     dev_info(dev->v4l2_dev.dev, "Unpacking/packing:   %u / %u\n",
> > +              get_field(reg, UNICAM_PUM_MASK),
> > +              get_field(reg, UNICAM_PPM_MASK));
> > +     dev_info(dev->v4l2_dev.dev, "----Live data----\n");
> > +     dev_info(dev->v4l2_dev.dev, "Programmed stride:   %4u\n",
> > +              reg_read(dev, UNICAM_IBLS));
> > +     dev_info(dev->v4l2_dev.dev, "Detected resolution: %ux%u\n",
> > +              reg_read(dev, UNICAM_IHSTA),
> > +              reg_read(dev, UNICAM_IVSTA));
> > +     dev_info(dev->v4l2_dev.dev, "Write pointer:       %08x\n",
> > +              reg_read(dev, UNICAM_IBWP));
> > +
> > +     return 0;
> > +}
> > +
> > +static int unicam_subscribe_event(struct v4l2_fh *fh,
> > +                               const struct v4l2_event_subscription *sub)
> > +{
> > +     switch (sub->type) {
> > +     case V4L2_EVENT_FRAME_SYNC:
> > +             return v4l2_event_subscribe(fh, sub, 2, NULL);
> > +     case V4L2_EVENT_SOURCE_CHANGE:
> > +             return v4l2_event_subscribe(fh, sub, 4, NULL);
>
> The drive doesn't generate V4L2_EVENT_SOURCE_CHANGE events, drop it.
>
> > +     }
> > +
> > +     return v4l2_ctrl_subscribe_event(fh, sub);
> > +}
> > +
> > +static void unicam_notify(struct v4l2_subdev *sd,
> > +                       unsigned int notification, void *arg)
> > +{
> > +     struct unicam_device *dev = to_unicam_device(sd->v4l2_dev);
>
> Use sd_to_unicam_device().
>
> > +
> > +     switch (notification) {
> > +     case V4L2_DEVICE_NOTIFY_EVENT:
> > +             v4l2_event_queue(&dev->node[IMAGE_NODE].video_dev, arg);
> > +             break;
> > +     default:
> > +             break;
> > +     }
> > +}
>
> Not needed, drop it.
>
> > +
> > +/* V4L2 Media Controller Centric IOCTLs */
> > +
> > +static int unicam_mc_enum_fmt_vid_cap(struct file *file, void  *priv,
> > +                                   struct v4l2_fmtdesc *f)
>
> Drop "mc" in all function names as that's the only option now.
>
> > +{
> > +     int i, j;
>
> Never negative, can be unsigned int.
>
> j is not a loop counter but the format index, I'd rename it to index to
> make it clearer.
>
> > +
> > +     for (i = 0, j = 0; i < ARRAY_SIZE(formats); i++) {
> > +             if (f->mbus_code && formats[i].code != f->mbus_code)
> > +                     continue;
> > +             if (formats[i].mc_skip || formats[i].metadata_fmt)
> > +                     continue;
> > +
> > +             if (formats[i].fourcc) {
>
> All entries have a fourcc so you can drop this check.
>
> > +                     if (j == f->index) {
> > +                             f->pixelformat = formats[i].fourcc;
> > +                             f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
>
> Not needed, the type is an input parameter. Same below.
>
> > +                             return 0;
> > +                     }
> > +                     j++;
> > +             }
> > +             if (formats[i].repacked_fourcc) {
> > +                     if (j == f->index) {
> > +                             f->pixelformat = formats[i].repacked_fourcc;
> > +                             f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> > +                             return 0;
> > +                     }
> > +                     j++;
> > +             }
> > +     }
> > +
> > +     return -EINVAL;
> > +}
> > +
> > +static int unicam_mc_g_fmt_vid_cap(struct file *file, void *priv,
> > +                                struct v4l2_format *f)
> > +{
> > +     struct unicam_node *node = video_drvdata(file);
> > +
> > +     if (!is_image_node(node))
> > +             return -EINVAL;
>
> Can this happen ?
>
> > +
> > +     *f = node->v_fmt;
> > +
> > +     return 0;
> > +}
> > +
> > +static void unicam_mc_try_fmt(struct unicam_node *node, struct v4l2_format *f,
> > +                           const struct unicam_fmt **ret_fmt)
> > +{
> > +     struct v4l2_pix_format *v4l2_format = &f->fmt.pix;
> > +     struct unicam_device *dev = node->dev;
> > +     const struct unicam_fmt *fmt;
> > +     int is_rgb;
>
> bool.
>
> > +
> > +     /*
> > +      * Default to the first format if the requested pixel format code isn't
> > +      * supported.
> > +      */
> > +     fmt = find_format_by_fourcc(v4l2_format->pixelformat);
> > +     if (!fmt) {
> > +             fmt = &formats[0];
> > +             v4l2_format->pixelformat = fmt->fourcc;
> > +     }
> > +
> > +     unicam_calc_format_size_bpl(dev, fmt, f);
> > +
> > +     if (v4l2_format->field == V4L2_FIELD_ANY)
> > +             v4l2_format->field = V4L2_FIELD_NONE;
> > +
> > +     if (v4l2_format->colorspace >= MAX_COLORSPACE ||
> > +         !(fmt->valid_colorspaces & (1 << v4l2_format->colorspace))) {
> > +             v4l2_format->colorspace = __ffs(fmt->valid_colorspaces);
> > +
> > +             v4l2_format->xfer_func =
> > +                     V4L2_MAP_XFER_FUNC_DEFAULT(v4l2_format->colorspace);
> > +             v4l2_format->ycbcr_enc =
> > +                     V4L2_MAP_YCBCR_ENC_DEFAULT(v4l2_format->colorspace);
> > +             is_rgb = v4l2_format->colorspace == V4L2_COLORSPACE_SRGB;
> > +             v4l2_format->quantization =
> > +                     V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb,
> > +                                                   v4l2_format->colorspace,
> > +                                                   v4l2_format->ycbcr_enc);
> > +     }
>
> Drop this, we can accept any colorspace produced by the sensor.
>
> > +
> > +     if (ret_fmt)
> > +             *ret_fmt = fmt;
>
> How about returning the format from the function instead ?
>
> > +
> > +     dev_dbg(dev->v4l2_dev.dev, "%s: %08x %ux%u (bytesperline %u sizeimage %u)\n",
> > +             __func__, v4l2_format->pixelformat,
> > +             v4l2_format->width, v4l2_format->height,
> > +             v4l2_format->bytesperline, v4l2_format->sizeimage);
> > +}
> > +
> > +static int unicam_mc_try_fmt_vid_cap(struct file *file, void *priv,
> > +                                  struct v4l2_format *f)
> > +{
> > +     struct unicam_node *node = video_drvdata(file);
> > +
> > +     unicam_mc_try_fmt(node, f, NULL);
> > +     return 0;
> > +}
> > +
> > +static int unicam_mc_s_fmt_vid_cap(struct file *file, void *priv,
> > +                                struct v4l2_format *f)
> > +{
> > +     struct unicam_node *node = video_drvdata(file);
> > +     struct unicam_device *dev = node->dev;
> > +     const struct unicam_fmt *fmt;
> > +
> > +     if (vb2_is_busy(&node->buffer_queue)) {
> > +             dev_dbg(dev->v4l2_dev.dev, "%s device busy\n", __func__);
> > +             return -EBUSY;
> > +     }
> > +
> > +     unicam_mc_try_fmt(node, f, &fmt);
> > +
> > +     node->v_fmt = *f;
> > +     node->fmt = fmt;
> > +
> > +     return 0;
> > +}
> > +
> > +static int unicam_mc_enum_framesizes(struct file *file, void *fh,
> > +                                  struct v4l2_frmsizeenum *fsize)
> > +{
> > +     struct unicam_node *node = video_drvdata(file);
> > +     struct unicam_device *dev = node->dev;
> > +
> > +     if (fsize->index > 0)
> > +             return -EINVAL;
> > +
> > +     if (!find_format_by_fourcc(fsize->pixel_format)) {
> > +             dev_dbg(dev->v4l2_dev.dev, "Invalid pixel format 0x%08x\n",
> > +                     fsize->pixel_format);
>
> I'd drop this message.
>
> > +             return -EINVAL;
> > +     }
> > +
> > +     fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
> > +     fsize->stepwise.min_width = MIN_WIDTH;
> > +     fsize->stepwise.max_width = MAX_WIDTH;
> > +     fsize->stepwise.step_width = 1;
> > +     fsize->stepwise.min_height = MIN_HEIGHT;
> > +     fsize->stepwise.max_height = MAX_HEIGHT;
> > +     fsize->stepwise.step_height = 1;
>
> Is this valid for the metadata node too ?
>
> > +
> > +     return 0;
> > +}
> > +
> > +static int unicam_mc_enum_fmt_meta_cap(struct file *file, void  *priv,
> > +                                    struct v4l2_fmtdesc *f)
> > +{
> > +     struct unicam_node *node = video_drvdata(file);
> > +     int i, j;
> > +
> > +     if (!is_metadata_node(node))
> > +             return -EINVAL;
>
> Same comments as for video format enumeration.
>
> > +
> > +     for (i = 0, j = 0; i < ARRAY_SIZE(formats); i++) {
> > +             if (f->mbus_code && formats[i].code != f->mbus_code)
> > +                     continue;
> > +             if (!formats[i].metadata_fmt)
> > +                     continue;
> > +
> > +             if (formats[i].fourcc) {
> > +                     if (j == f->index) {
> > +                             f->pixelformat = formats[i].fourcc;
> > +                             f->type = V4L2_BUF_TYPE_META_CAPTURE;
> > +                             return 0;
> > +                     }
> > +                     j++;
> > +             }
> > +     }
> > +
> > +     return -EINVAL;
> > +}
> > +
> > +static int unicam_mc_g_fmt_meta_cap(struct file *file, void *priv,
> > +                                 struct v4l2_format *f)
> > +{
> > +     struct unicam_node *node = video_drvdata(file);
> > +
> > +     if (!is_metadata_node(node))
> > +             return -EINVAL;
>
> Can this happen ? Same below.
>
> > +
> > +     *f = node->v_fmt;
> > +
> > +     return 0;
> > +}
> > +
> > +static int unicam_mc_try_fmt_meta_cap(struct file *file, void *priv,
> > +                                   struct v4l2_format *f)
> > +{
> > +     struct unicam_node *node = video_drvdata(file);
> > +
> > +     if (!is_metadata_node(node))
> > +             return -EINVAL;
> > +
> > +     f->fmt.meta.dataformat = V4L2_META_FMT_8;
> > +
> > +     return 0;
> > +}
> > +
> > +static int unicam_mc_s_fmt_meta_cap(struct file *file, void *priv,
> > +                                 struct v4l2_format *f)
> > +{
> > +     struct unicam_node *node = video_drvdata(file);
> > +
> > +     if (!is_metadata_node(node))
> > +             return -EINVAL;
> > +
> > +     unicam_mc_try_fmt_meta_cap(file, priv, f);
> > +
> > +     node->v_fmt = *f;
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct v4l2_ioctl_ops unicam_mc_ioctl_ops = {
> > +     .vidioc_querycap      = unicam_querycap,
> > +     .vidioc_enum_fmt_vid_cap  = unicam_mc_enum_fmt_vid_cap,
> > +     .vidioc_g_fmt_vid_cap     = unicam_mc_g_fmt_vid_cap,
> > +     .vidioc_try_fmt_vid_cap   = unicam_mc_try_fmt_vid_cap,
> > +     .vidioc_s_fmt_vid_cap     = unicam_mc_s_fmt_vid_cap,
> > +
> > +     .vidioc_enum_fmt_meta_cap       = unicam_mc_enum_fmt_meta_cap,
> > +     .vidioc_g_fmt_meta_cap          = unicam_mc_g_fmt_meta_cap,
> > +     .vidioc_try_fmt_meta_cap        = unicam_mc_try_fmt_meta_cap,
> > +     .vidioc_s_fmt_meta_cap          = unicam_mc_s_fmt_meta_cap,
> > +
> > +     .vidioc_enum_framesizes   = unicam_mc_enum_framesizes,
> > +     .vidioc_reqbufs       = vb2_ioctl_reqbufs,
> > +     .vidioc_create_bufs   = vb2_ioctl_create_bufs,
> > +     .vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
> > +     .vidioc_querybuf      = vb2_ioctl_querybuf,
> > +     .vidioc_qbuf          = vb2_ioctl_qbuf,
> > +     .vidioc_dqbuf         = vb2_ioctl_dqbuf,
> > +     .vidioc_expbuf        = vb2_ioctl_expbuf,
> > +     .vidioc_streamon      = vb2_ioctl_streamon,
> > +     .vidioc_streamoff     = vb2_ioctl_streamoff,
> > +
> > +     .vidioc_log_status              = unicam_log_status,
> > +     .vidioc_subscribe_event         = unicam_subscribe_event,
> > +     .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
> > +};
> > +
> > +static const struct media_entity_operations unicam_mc_entity_ops = {
> > +     .link_validate = v4l2_subdev_link_validate,
> > +     .has_route = v4l2_subdev_has_route,
> > +};
>
> I don't think this is needed for the video nodes.
>
> > +
> > +/* videobuf2 Operations */
> > +
> > +static int unicam_queue_setup(struct vb2_queue *vq,
> > +                           unsigned int *nbuffers,
> > +                           unsigned int *nplanes,
> > +                           unsigned int sizes[],
> > +                           struct device *alloc_devs[])
> > +{
> > +     struct unicam_node *node = vb2_get_drv_priv(vq);
> > +     struct unicam_device *dev = node->dev;
> > +     unsigned int size = is_image_node(node) ?
> > +                             node->v_fmt.fmt.pix.sizeimage :
> > +                             node->v_fmt.fmt.meta.buffersize;
> > +
> > +     if (vq->num_buffers + *nbuffers < 3)
> > +             *nbuffers = 3 - vq->num_buffers;
> > +
> > +     if (*nplanes) {
> > +             if (sizes[0] < size) {
> > +                     dev_err(dev->v4l2_dev.dev, "sizes[0] %i < size %u\n", sizes[0],
> > +                             size);
>
> This can be a debug message, let's not give a way to unprivileged
> userspace to flood the kernel log.
>
> > +                     return -EINVAL;
> > +             }
> > +             size = sizes[0];
> > +     }
> > +
> > +     *nplanes = 1;
> > +     sizes[0] = size;
> > +
> > +     return 0;
> > +}
> > +
> > +static int unicam_buffer_prepare(struct vb2_buffer *vb)
> > +{
> > +     struct unicam_node *node = vb2_get_drv_priv(vb->vb2_queue);
> > +     struct unicam_device *dev = node->dev;
> > +     struct unicam_buffer *buf = to_unicam_buffer(vb);
> > +     unsigned long size;
> > +
> > +     if (WARN_ON(!node->fmt))
> > +             return -EINVAL;
> > +
> > +     size = is_image_node(node) ? node->v_fmt.fmt.pix.sizeimage :
> > +                                  node->v_fmt.fmt.meta.buffersize;
> > +     if (vb2_plane_size(vb, 0) < size) {
> > +             dev_err(dev->v4l2_dev.dev, "data will not fit into plane (%lu < %lu)\n",
> > +                     vb2_plane_size(vb, 0), size);
>
> Debug message here too.
>
> > +             return -EINVAL;
> > +     }
> > +
> > +     vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size);
> > +     return 0;
> > +}
> > +
> > +static void unicam_buffer_queue(struct vb2_buffer *vb)
> > +{
> > +     struct unicam_node *node = vb2_get_drv_priv(vb->vb2_queue);
> > +     struct unicam_buffer *buf = to_unicam_buffer(vb);
> > +     unsigned long flags;
> > +
> > +     spin_lock_irqsave(&node->dma_queue_lock, flags);
>
> Small optimization, as this is guaranteed to be called with interrupts
> enabled, you can use the spin_lock_irq() variant.
>
> > +     list_add_tail(&buf->list, &node->dma_queue);
> > +     spin_unlock_irqrestore(&node->dma_queue_lock, flags);
> > +}
> > +
> > +static void unicam_set_packing_config(struct unicam_device *dev)
> > +{
> > +     u32 pack, unpack;
> > +     u32 val;
> > +
> > +     if (dev->node[IMAGE_NODE].v_fmt.fmt.pix.pixelformat ==
> > +         dev->node[IMAGE_NODE].fmt->fourcc) {
> > +             unpack = UNICAM_PUM_NONE;
> > +             pack = UNICAM_PPM_NONE;
> > +     } else {
> > +             switch (dev->node[IMAGE_NODE].fmt->depth) {
> > +             case 8:
> > +                     unpack = UNICAM_PUM_UNPACK8;
> > +                     break;
> > +             case 10:
> > +                     unpack = UNICAM_PUM_UNPACK10;
> > +                     break;
> > +             case 12:
> > +                     unpack = UNICAM_PUM_UNPACK12;
> > +                     break;
> > +             case 14:
> > +                     unpack = UNICAM_PUM_UNPACK14;
> > +                     break;
> > +             case 16:
> > +                     unpack = UNICAM_PUM_UNPACK16;
> > +                     break;
> > +             default:
> > +                     unpack = UNICAM_PUM_NONE;
> > +                     break;
> > +             }
> > +
> > +             /* Repacking is always to 16bpp */
> > +             pack = UNICAM_PPM_PACK16;
> > +     }
> > +
> > +     val = 0;
> > +     set_field(&val, unpack, UNICAM_PUM_MASK);
> > +     set_field(&val, pack, UNICAM_PPM_MASK);
> > +     reg_write(dev, UNICAM_IPIPE, val);
> > +}
> > +
> > +static void unicam_cfg_image_id(struct unicam_device *dev)
> > +{
> > +     if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > +             /* CSI2 mode, hardcode VC 0 for now. */
> > +             reg_write(dev, UNICAM_IDI0,
> > +                       (0 << 6) | dev->node[IMAGE_NODE].fmt->csi_dt);
> > +     } else {
> > +             /* CCP2 mode */
> > +             reg_write(dev, UNICAM_IDI0,
> > +                       0x80 | dev->node[IMAGE_NODE].fmt->csi_dt);
> > +     }
> > +}
> > +
> > +static void unicam_enable_ed(struct unicam_device *dev)
> > +{
> > +     u32 val = reg_read(dev, UNICAM_DCS);
> > +
> > +     set_field(&val, 2, UNICAM_EDL_MASK);
> > +     /* Do not wrap at the end of the embedded data buffer */
> > +     set_field(&val, 0, UNICAM_DBOB);
> > +
> > +     reg_write(dev, UNICAM_DCS, val);
> > +}
> > +
> > +static void unicam_start_rx(struct unicam_device *dev, dma_addr_t *addr)
> > +{
> > +     int line_int_freq = dev->node[IMAGE_NODE].v_fmt.fmt.pix.height >> 2;
> > +     unsigned int size, i;
> > +     u32 val;
> > +
> > +     if (line_int_freq < 128)
> > +             line_int_freq = 128;
> > +
> > +     /* Enable lane clocks */
> > +     val = 1;
> > +     for (i = 0; i < dev->active_data_lanes; i++)
> > +             val = val << 2 | 1;
> > +     clk_write(dev, val);
> > +
> > +     /* Basic init */
> > +     reg_write(dev, UNICAM_CTRL, UNICAM_MEM);
> > +
> > +     /* Enable analogue control, and leave in reset. */
> > +     val = UNICAM_AR;
> > +     set_field(&val, 7, UNICAM_CTATADJ_MASK);
> > +     set_field(&val, 7, UNICAM_PTATADJ_MASK);
> > +     reg_write(dev, UNICAM_ANA, val);
> > +     usleep_range(1000, 2000);
> > +
> > +     /* Come out of reset */
> > +     reg_write_field(dev, UNICAM_ANA, 0, UNICAM_AR);
> > +
> > +     /* Peripheral reset */
> > +     reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_CPR);
> > +     reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPR);
> > +
> > +     reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPE);
> > +
> > +     /* Enable Rx control. */
> > +     val = reg_read(dev, UNICAM_CTRL);
> > +     if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > +             set_field(&val, UNICAM_CPM_CSI2, UNICAM_CPM_MASK);
> > +             set_field(&val, UNICAM_DCM_STROBE, UNICAM_DCM_MASK);
> > +     } else {
> > +             set_field(&val, UNICAM_CPM_CCP2, UNICAM_CPM_MASK);
> > +             set_field(&val, dev->bus_flags, UNICAM_DCM_MASK);
> > +     }
> > +     /* Packet framer timeout */
> > +     set_field(&val, 0xf, UNICAM_PFT_MASK);
> > +     set_field(&val, 128, UNICAM_OET_MASK);
> > +     reg_write(dev, UNICAM_CTRL, val);
> > +
> > +     reg_write(dev, UNICAM_IHWIN, 0);
> > +     reg_write(dev, UNICAM_IVWIN, 0);
> > +
> > +     /* AXI bus access QoS setup */
> > +     val = reg_read(dev, UNICAM_PRI);
> > +     set_field(&val, 0, UNICAM_BL_MASK);
> > +     set_field(&val, 0, UNICAM_BS_MASK);
> > +     set_field(&val, 0xe, UNICAM_PP_MASK);
> > +     set_field(&val, 8, UNICAM_NP_MASK);
> > +     set_field(&val, 2, UNICAM_PT_MASK);
> > +     set_field(&val, 1, UNICAM_PE);
> > +     reg_write(dev, UNICAM_PRI, val);
> > +
> > +     reg_write_field(dev, UNICAM_ANA, 0, UNICAM_DDL);
> > +
> > +     /* Always start in trigger frame capture mode (UNICAM_FCM set) */
> > +     val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM | UNICAM_IBOB;
> > +     set_field(&val, line_int_freq, UNICAM_LCIE_MASK);
> > +     reg_write(dev, UNICAM_ICTL, val);
> > +     reg_write(dev, UNICAM_STA, UNICAM_STA_MASK_ALL);
> > +     reg_write(dev, UNICAM_ISTA, UNICAM_ISTA_MASK_ALL);
> > +
> > +     /* tclk_term_en */
> > +     reg_write_field(dev, UNICAM_CLT, 2, UNICAM_CLT1_MASK);
> > +     /* tclk_settle */
> > +     reg_write_field(dev, UNICAM_CLT, 6, UNICAM_CLT2_MASK);
> > +     /* td_term_en */
> > +     reg_write_field(dev, UNICAM_DLT, 2, UNICAM_DLT1_MASK);
> > +     /* ths_settle */
> > +     reg_write_field(dev, UNICAM_DLT, 6, UNICAM_DLT2_MASK);
> > +     /* trx_enable */
> > +     reg_write_field(dev, UNICAM_DLT, 0, UNICAM_DLT3_MASK);
> > +
> > +     reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_SOE);
> > +
> > +     /* Packet compare setup - required to avoid missing frame ends */
> > +     val = 0;
> > +     set_field(&val, 1, UNICAM_PCE);
> > +     set_field(&val, 1, UNICAM_GI);
> > +     set_field(&val, 1, UNICAM_CPH);
> > +     set_field(&val, 0, UNICAM_PCVC_MASK);
> > +     set_field(&val, 1, UNICAM_PCDT_MASK);
> > +     reg_write(dev, UNICAM_CMP0, val);
> > +
> > +     /* Enable clock lane and set up terminations */
> > +     val = 0;
> > +     if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > +             /* CSI2 */
> > +             set_field(&val, 1, UNICAM_CLE);
> > +             set_field(&val, 1, UNICAM_CLLPE);
> > +             if (dev->bus_flags & V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) {
> > +                     set_field(&val, 1, UNICAM_CLTRE);
> > +                     set_field(&val, 1, UNICAM_CLHSE);
> > +             }
> > +     } else {
> > +             /* CCP2 */
> > +             set_field(&val, 1, UNICAM_CLE);
> > +             set_field(&val, 1, UNICAM_CLHSE);
> > +             set_field(&val, 1, UNICAM_CLTRE);
> > +     }
> > +     reg_write(dev, UNICAM_CLK, val);
> > +
> > +     /*
> > +      * Enable required data lanes with appropriate terminations.
> > +      * The same value needs to be written to UNICAM_DATn registers for
> > +      * the active lanes, and 0 for inactive ones.
> > +      */
> > +     val = 0;
> > +     if (dev->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > +             /* CSI2 */
> > +             set_field(&val, 1, UNICAM_DLE);
> > +             set_field(&val, 1, UNICAM_DLLPE);
> > +             if (dev->bus_flags & V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) {
> > +                     set_field(&val, 1, UNICAM_DLTRE);
> > +                     set_field(&val, 1, UNICAM_DLHSE);
> > +             }
> > +     } else {
> > +             /* CCP2 */
> > +             set_field(&val, 1, UNICAM_DLE);
> > +             set_field(&val, 1, UNICAM_DLHSE);
> > +             set_field(&val, 1, UNICAM_DLTRE);
> > +     }
> > +     reg_write(dev, UNICAM_DAT0, val);
> > +
> > +     if (dev->active_data_lanes == 1)
> > +             val = 0;
> > +     reg_write(dev, UNICAM_DAT1, val);
> > +
> > +     if (dev->max_data_lanes > 2) {
> > +             /*
> > +              * Registers UNICAM_DAT2 and UNICAM_DAT3 only valid if the
> > +              * instance supports more than 2 data lanes.
> > +              */
> > +             if (dev->active_data_lanes == 2)
> > +                     val = 0;
> > +             reg_write(dev, UNICAM_DAT2, val);
> > +
> > +             if (dev->active_data_lanes == 3)
> > +                     val = 0;
> > +             reg_write(dev, UNICAM_DAT3, val);
> > +     }
> > +
> > +     reg_write(dev, UNICAM_IBLS,
> > +               dev->node[IMAGE_NODE].v_fmt.fmt.pix.bytesperline);
> > +     size = dev->node[IMAGE_NODE].v_fmt.fmt.pix.sizeimage;
> > +     unicam_wr_dma_addr(dev, addr[IMAGE_NODE], size, IMAGE_NODE);
> > +     unicam_set_packing_config(dev);
> > +     unicam_cfg_image_id(dev);
> > +
> > +     val = reg_read(dev, UNICAM_MISC);
> > +     set_field(&val, 1, UNICAM_FL0);
> > +     set_field(&val, 1, UNICAM_FL1);
> > +     reg_write(dev, UNICAM_MISC, val);
> > +
> > +     if (dev->node[METADATA_NODE].streaming && dev->sensor_embedded_data) {
> > +             dev_dbg(dev->v4l2_dev.dev, "enable metadata dma\n");
> > +             size = dev->node[METADATA_NODE].v_fmt.fmt.meta.buffersize;
> > +             unicam_enable_ed(dev);
> > +             unicam_wr_dma_addr(dev, addr[METADATA_NODE], size, METADATA_NODE);
> > +     }
> > +
> > +     /* Enable peripheral */
> > +     reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_CPE);
> > +
> > +     /* Load image pointers */
> > +     reg_write_field(dev, UNICAM_ICTL, 1, UNICAM_LIP_MASK);
> > +
> > +     /* Load embedded data buffer pointers if needed */
> > +     if (dev->node[METADATA_NODE].streaming && dev->sensor_embedded_data)
> > +             reg_write_field(dev, UNICAM_DCS, 1, UNICAM_LDP);
> > +
> > +     /*
> > +      * Enable trigger only for the first frame to
> > +      * sync correctly to the FS from the source.
> > +      */
> > +     reg_write_field(dev, UNICAM_ICTL, 1, UNICAM_TFC);
> > +}
> > +
> > +static void unicam_disable(struct unicam_device *dev)
> > +{
> > +     /* Analogue lane control disable */
> > +     reg_write_field(dev, UNICAM_ANA, 1, UNICAM_DDL);
> > +
> > +     /* Stop the output engine */
> > +     reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_SOE);
> > +
> > +     /* Disable the data lanes. */
> > +     reg_write(dev, UNICAM_DAT0, 0);
> > +     reg_write(dev, UNICAM_DAT1, 0);
> > +
> > +     if (dev->max_data_lanes > 2) {
> > +             reg_write(dev, UNICAM_DAT2, 0);
> > +             reg_write(dev, UNICAM_DAT3, 0);
> > +     }
> > +
> > +     /* Peripheral reset */
> > +     reg_write_field(dev, UNICAM_CTRL, 1, UNICAM_CPR);
> > +     usleep_range(50, 100);
> > +     reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPR);
> > +
> > +     /* Disable peripheral */
> > +     reg_write_field(dev, UNICAM_CTRL, 0, UNICAM_CPE);
> > +
> > +     /* Clear ED setup */
> > +     reg_write(dev, UNICAM_DCS, 0);
> > +
> > +     /* Disable all lane clocks */
> > +     clk_write(dev, 0);
> > +}
> > +
> > +static void unicam_return_buffers(struct unicam_node *node,
> > +                               enum vb2_buffer_state state)
> > +{
> > +     struct unicam_buffer *buf, *tmp;
> > +     unsigned long flags;
> > +
> > +     spin_lock_irqsave(&node->dma_queue_lock, flags);
>
> Same here, spin_lock_irq() would do. But isn't this function meant to be
> called with the hardware stopped ? Shouldn't it then be safe to drop the
> spinlock completely ?
>
> > +     list_for_each_entry_safe(buf, tmp, &node->dma_queue, list) {
> > +             list_del(&buf->list);
> > +             vb2_buffer_done(&buf->vb.vb2_buf, state);
> > +     }
> > +
> > +     if (node->cur_frm)
> > +             vb2_buffer_done(&node->cur_frm->vb.vb2_buf,
> > +                             state);
> > +     if (node->next_frm && node->cur_frm != node->next_frm)
> > +             vb2_buffer_done(&node->next_frm->vb.vb2_buf,
> > +                             state);
> > +
> > +     node->cur_frm = NULL;
> > +     node->next_frm = NULL;
> > +     spin_unlock_irqrestore(&node->dma_queue_lock, flags);
> > +}
> > +
> > +static int unicam_video_check_format(struct unicam_node *node)
> > +{
> > +     const struct v4l2_mbus_framefmt *format;
> > +     struct media_pad *remote_pad;
> > +     struct v4l2_subdev_state *state;
> > +     int ret = 0;
> > +
> > +     remote_pad = media_entity_remote_pad(&node->pad);
> > +     if (!remote_pad)
> > +             return -ENODEV;
>
> This could be done in unicam_async_complete() and cached in the
> unicam_device structure, the same way we cache the sensor subdev
> pointer.
>
> > +
> > +     state = v4l2_subdev_lock_active_state(node->dev->sensor);
>
> That's not correct, the video node is connected to the subdev, not to
> the sensor.
>
> > +
> > +     format = v4l2_state_get_stream_format(state,
> > +                                           remote_pad->index, 0);
>
> This holds on a single line.
>
> > +     if (!format) {
> > +             ret = -EINVAL;
> > +             goto out;
> > +     }
> > +
> > +     if (node->fmt->code != format->code ||
> > +         node->v_fmt.fmt.pix.height != format->height ||
> > +         node->v_fmt.fmt.pix.width != format->width ||
> > +         node->v_fmt.fmt.pix.field != format->field) {
>
> A debug message that prints the configuration on both sides could be
> useful for debugging here.
>
> > +             ret = -EPIPE;
> > +             goto out;
> > +     }
> > +
> > +out:
> > +     v4l2_subdev_unlock_state(state);
> > +
> > +     return ret;
> > +}
> > +
> > +static int unicam_start_streaming(struct vb2_queue *vq, unsigned int count)
> > +{
> > +     struct unicam_node *node = vb2_get_drv_priv(vq);
> > +     struct unicam_device *dev = node->dev;
> > +     dma_addr_t buffer_addr[MAX_NODES] = { 0 };
> > +     struct unicam_buffer *buf;
> > +     unsigned long flags;
> > +     unsigned int i;
> > +     int ret;
> > +
> > +     node->streaming = true;
>
> Locking seems to be completely missing from the driver. I'll comment
> more on that on v3, it will be easier after all the other cleanups.
>
> > +
> > +     dev->sequence = 0;
> > +     ret = unicam_runtime_get(dev);
> > +     if (ret < 0) {
> > +             dev_dbg(dev->v4l2_dev.dev, "unicam_runtime_get failed\n");
>
> This is really not supposed to happen, dev_err() is appropriate.
>
> > +             goto err_streaming;
> > +     }
> > +
> > +     ret = media_pipeline_start(node->video_dev.entity.pads, &node->pipe);
> > +     if (ret < 0) {
> > +             dev_err(dev->v4l2_dev.dev, "Failed to start media pipeline: %d\n", ret);
>
> dev_dbg() here too.
>
> > +             goto err_pm_put;
> > +     }
> > +
> > +     dev->active_data_lanes = dev->max_data_lanes;
>
> You need to get the number of data lanes from the sensor subdev and
> validate it to ensure it doesn't exceed the maximum.
>
> > +
> > +     unicam_video_check_format(node);
>
> Where's the return value check ?
>
> > +
> > +     dev_dbg(dev->v4l2_dev.dev, "Running with %u data lanes\n",
> > +             dev->active_data_lanes);
> > +
> > +     ret = clk_set_min_rate(dev->vpu_clock, MIN_VPU_CLOCK_RATE);
> > +     if (ret) {
> > +             dev_err(dev->v4l2_dev.dev, "failed to set up VPU clock\n");
> > +             goto error_pipeline;
> > +     }
> > +
> > +     ret = clk_prepare_enable(dev->vpu_clock);
> > +     if (ret) {
> > +             dev_err(dev->v4l2_dev.dev, "Failed to enable VPU clock: %d\n", ret);
> > +             goto error_pipeline;
> > +     }
> > +
> > +     ret = clk_set_rate(dev->clock, 100 * 1000 * 1000);
> > +     if (ret) {
> > +             dev_err(dev->v4l2_dev.dev, "failed to set up CSI clock\n");
> > +             goto err_vpu_clock;
> > +     }
> > +
> > +     ret = clk_prepare_enable(dev->clock);
> > +     if (ret) {
> > +             dev_err(dev->v4l2_dev.dev, "Failed to enable CSI clock: %d\n", ret);
> > +             goto err_vpu_clock;
> > +     }
> > +
> > +     dev_dbg(dev->v4l2_dev.dev, "node %s\n", node->video_dev.name);
> > +
> > +     spin_lock_irqsave(&node->dma_queue_lock, flags);
> > +     buf = list_first_entry(&node->dma_queue,
> > +                            struct unicam_buffer, list);
>
> This holds on a single line.
>
> > +     node->cur_frm = buf;
> > +     node->next_frm = buf;
> > +     list_del(&buf->list);
> > +     spin_unlock_irqrestore(&node->dma_queue_lock, flags);
> > +
> > +     buffer_addr[i] =
> > +             vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
>
> This too.
>
> > +
> > +     unicam_start_rx(dev, buffer_addr);
> > +
> > +     ret = v4l2_subdev_call(&dev->sd, video, s_stream, 1);
> > +     if (ret < 0) {
> > +             dev_err(dev->v4l2_dev.dev, "stream on failed in subdev\n");
> > +             goto err_disable_unicam;
> > +     }
>
> Do I understand correctly that all this will run twice, once when
> VIDIOC_STREAMON is called on the image node, and once when it's called
> on the metadata node ? That doesn't seem right. The stop_streaming
> function is affected similarly.
>
> > +
> > +     dev->clocks_enabled = true;
> > +     return 0;
> > +
> > +err_disable_unicam:
> > +     unicam_disable(dev);
> > +     clk_disable_unprepare(dev->clock);
> > +err_vpu_clock:
> > +     if (clk_set_min_rate(dev->vpu_clock, 0))
> > +             dev_err(dev->v4l2_dev.dev, "failed to reset the VPU clock\n");
> > +     clk_disable_unprepare(dev->vpu_clock);
> > +error_pipeline:
> > +     media_pipeline_stop(node->video_dev.entity.pads);
> > +err_pm_put:
> > +     unicam_runtime_put(dev);
> > +err_streaming:
> > +     unicam_return_buffers(node, VB2_BUF_STATE_QUEUED);
> > +     node->streaming = false;
> > +
> > +     return ret;
> > +}
> > +
> > +static void unicam_stop_streaming(struct vb2_queue *vq)
> > +{
> > +     struct unicam_node *node = vb2_get_drv_priv(vq);
> > +     struct unicam_device *dev = node->dev;
> > +
> > +     node->streaming = false;
> > +     /*
> > +      * Stop streaming the sensor and disable the peripheral.
> > +      * We cannot continue streaming embedded data with the
> > +      * image pad disabled.
> > +      */
> > +     if (v4l2_subdev_call(&dev->sd, video, s_stream, 0) < 0)
> > +             dev_err(dev->v4l2_dev.dev, "stream off failed in subdev\n");
> > +
> > +     unicam_disable(dev);
> > +
> > +     media_pipeline_stop(node->video_dev.entity.pads);
> > +
> > +     if (dev->clocks_enabled) {
>
> .stop_streaming() can only be called after a successful
> .start_streaming() call, so you can drop the clocks_enabled field.
>
> > +             if (clk_set_min_rate(dev->vpu_clock, 0))
> > +                     dev_err(dev->v4l2_dev.dev, "failed to reset the VPU clock\n");
> > +             clk_disable_unprepare(dev->vpu_clock);
> > +             clk_disable_unprepare(dev->clock);
> > +             dev->clocks_enabled = false;
> > +     }
> > +     unicam_runtime_put(dev);
> > +
> > +     if (is_metadata_node(node)) {
> > +             /*
> > +              * Allow the hardware to spin in the dummy buffer.
> > +              * This is only really needed if the embedded data pad is
> > +              * disabled before the image pad.
> > +              */
> > +             unicam_wr_dma_addr(dev, node->dummy_buf_dma_addr,
> > +                                DUMMY_BUF_SIZE, METADATA_NODE);
> > +     }
> > +
> > +     /* Clear all queued buffers for the node */
> > +     unicam_return_buffers(node, VB2_BUF_STATE_ERROR);
> > +}
> > +
> > +static const struct vb2_ops unicam_video_qops = {
> > +     .wait_prepare           = vb2_ops_wait_prepare,
> > +     .wait_finish            = vb2_ops_wait_finish,
> > +     .queue_setup            = unicam_queue_setup,
> > +     .buf_prepare            = unicam_buffer_prepare,
> > +     .buf_queue              = unicam_buffer_queue,
> > +     .start_streaming        = unicam_start_streaming,
> > +     .stop_streaming         = unicam_stop_streaming,
> > +};
> > +
> > +/* unicam capture driver file operations */
> > +static const struct v4l2_file_operations unicam_fops = {
> > +     .owner          = THIS_MODULE,
> > +     .open           = v4l2_fh_open,
> > +     .release        = vb2_fop_release,
> > +     .poll           = vb2_fop_poll,
> > +     .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
>
> Drop the comment.
>
> > +     .mmap           = vb2_fop_mmap,
> > +};
> > +
> > +static int
> > +unicam_async_bound(struct v4l2_async_notifier *notifier,
> > +                struct v4l2_subdev *subdev,
> > +                struct v4l2_async_subdev *asd)
> > +{
> > +     struct unicam_device *unicam = to_unicam_device(notifier->v4l2_dev);
> > +
> > +     if (unicam->sensor) {
> > +             dev_info(unicam->v4l2_dev.dev, "subdev %s (Already set!!)",
> > +                      subdev->name);
> > +             return 0;
> > +     }
>
> This can't happen as we register a single asd only.
>
> > +
> > +     unicam->sensor = subdev;
> > +     dev_dbg(unicam->v4l2_dev.dev, "Using sensor %s for capture\n", subdev->name);
>
> Line wrap.
>
> > +
> > +     return 0;
> > +}
> > +
> > +static void unicam_release(struct kref *kref)
> > +{
> > +     struct unicam_device *unicam =
> > +             container_of(kref, struct unicam_device, kref);
> > +
> > +     v4l2_ctrl_handler_free(&unicam->ctrl_handler);
> > +     media_device_cleanup(&unicam->mdev);
> > +
> > +     if (unicam->sensor_state)
> > +             __v4l2_subdev_state_free(unicam->sensor_state);
> > +
> > +     kfree(unicam);
> > +}
> > +
> > +static void unicam_put(struct unicam_device *unicam)
> > +{
> > +     kref_put(&unicam->kref, unicam_release);
> > +}
> > +
> > +static void unicam_get(struct unicam_device *unicam)
> > +{
> > +     kref_get(&unicam->kref);
> > +}
> > +
> > +static void unicam_node_release(struct video_device *vdev)
> > +{
> > +     struct unicam_node *node = video_get_drvdata(vdev);
> > +
> > +     unicam_put(node->dev);
> > +}
> > +
> > +static void unicam_mc_set_default_format(struct unicam_node *node)
> > +{
> > +     dev_dbg(node->dev->v4l2_dev.dev, "Set default format for %s node\n",
>
> node->dev->dev should do, no need to go through v4l2_dev here. But I'd
> drop the message, I don't think it brings much value.
>
> > +             node->node_id == IMAGE_NODE ? "image" : "metadata");
> > +
> > +     if (is_image_node(node)) {
> > +             struct v4l2_pix_format *pix_fmt = &node->v_fmt.fmt.pix;
> > +
> > +             pix_fmt->width = 640;
> > +             pix_fmt->height = 480;
> > +             pix_fmt->field = V4L2_FIELD_NONE;
> > +             pix_fmt->colorspace = V4L2_COLORSPACE_SRGB;
> > +             pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
> > +             pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE;
> > +             pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB;
> > +             pix_fmt->pixelformat = formats[0].fourcc;
> > +             unicam_calc_format_size_bpl(node->dev, &formats[0],
> > +                                         &node->v_fmt);
> > +             node->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> > +
> > +             node->fmt = &formats[0];
> > +     } else {
> > +             const struct unicam_fmt *fmt;
> > +
> > +             /* Fix this node format as embedded data. */
> > +             fmt = find_format_by_code(MEDIA_BUS_FMT_METADATA_8);
> > +             node->v_fmt.fmt.meta.dataformat = fmt->fourcc;
> > +             node->fmt = fmt;
>
> Move this to the end to group all v_fmt initialization together.
>
> > +             node->v_fmt.fmt.meta.buffersize = UNICAM_EMBEDDED_SIZE;
> > +             node->embedded_lines = 1;
>
> This belongs to the called.
>
> > +             node->v_fmt.type = V4L2_BUF_TYPE_META_CAPTURE;
> > +     }
> > +}
> > +
> > +static int register_node(struct unicam_device *unicam, struct unicam_node *node,
> > +                      enum v4l2_buf_type type)
>
> Replace the type parameter with a enum unicam_node_type, that will look
> cleaner in
>
> > +{
> > +     struct video_device *vdev;
> > +     struct vb2_queue *q;
> > +     int ret;
> > +
> > +     node->dev = unicam;
> > +     node->node_id = type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
> > +                             IMAGE_NODE :
> > +                             METADATA_NODE;
> > +
> > +     spin_lock_init(&node->dma_queue_lock);
> > +     mutex_init(&node->lock);
> > +
> > +     vdev = &node->video_dev;
> > +     /*
> > +      * If the sensor subdevice has any controls, associate the node
> > +      *  with the ctrl handler to allow access from userland.
> > +      */
> > +     if (!list_empty(&unicam->ctrl_handler.ctrls))
> > +             vdev->ctrl_handler = &unicam->ctrl_handler;
>
> Drop this, and move the vdev assignment below, just before it gets used.
>
>         /* Initialize the videobuf2 queue. */
> > +
> > +     q = &node->buffer_queue;
> > +     q->type = type;
> > +     q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
>
> Drop VB2_READ, that shouldn't be used.
>
> > +     q->drv_priv = node;
> > +     q->ops = &unicam_video_qops;
> > +     q->mem_ops = &vb2_dma_contig_memops;
> > +     q->buf_struct_size = sizeof(struct unicam_buffer);
> > +     q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> > +     q->lock = &node->lock;
> > +     q->min_buffers_needed = 1;
> > +     q->dev = &unicam->pdev->dev;
> > +
> > +     ret = vb2_queue_init(q);
> > +     if (ret) {
> > +             dev_err(unicam->v4l2_dev.dev, "vb2_queue_init() failed\n");
> > +             return ret;
> > +     }
> > +
> > +     INIT_LIST_HEAD(&node->dma_queue);
>
> Move this to the beginning of the function with the rest of the node
> initialization.
>
>         /* Initialize the video device. */
>
> > +
> > +     vdev->release = unicam_node_release;
> > +     vdev->fops = &unicam_fops;
> > +     vdev->ioctl_ops = &unicam_mc_ioctl_ops;
> > +     vdev->v4l2_dev = &unicam->v4l2_dev;
> > +     vdev->vfl_dir = VFL_DIR_RX;
> > +     vdev->queue = q;
> > +     vdev->lock = &node->lock;
> > +     vdev->device_caps = (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
>
> No need for parentheses.
>
> > +                             V4L2_CAP_VIDEO_CAPTURE : V4L2_CAP_META_CAPTURE;
> > +     vdev->device_caps |= V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_IO_MC;
>
> Drop V4L2_CAP_READWRITE.
>
> > +     vdev->entity.ops = &unicam_mc_entity_ops;
> > +
> > +     /* Define the device names */
> > +     snprintf(vdev->name, sizeof(vdev->name), "%s-%s", UNICAM_MODULE_NAME,
> > +              type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "image" : "embedded");
> > +
> > +     video_set_drvdata(vdev, node);
> > +     if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
> > +             vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT;
> > +     node->pad.flags = MEDIA_PAD_FL_SINK;
> > +     media_entity_pads_init(&vdev->entity, 1, &node->pad);
>
> Error check.
>
> > +
> > +     node->dummy_buf_cpu_addr = dma_alloc_coherent(&unicam->pdev->dev,
> > +                                                   DUMMY_BUF_SIZE,
> > +                                                   &node->dummy_buf_dma_addr,
> > +                                                   GFP_KERNEL);
> > +     if (!node->dummy_buf_cpu_addr) {
> > +             dev_err(unicam->v4l2_dev.dev, "Unable to allocate dummy buffer.\n");
> > +             return -ENOMEM;
> > +     }
> > +
> > +     ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
> > +     if (ret) {
> > +             dev_err(unicam->v4l2_dev.dev, "Unable to register video device %s\n",
> > +                     vdev->name);
> > +             return ret;
> > +     }
> > +
> > +     /*
> > +      * Acquire a reference to unicam, which will be released when the video
> > +      * device will be unregistered and userspace will have closed all open
> > +      * file handles.
> > +      */
> > +     unicam_get(unicam);
>
> This is error-prone. References should be acquired when stored, so this
> should be moved to the beginning of the function, and written as
>
>         node->dev = unicam_get(unicam);
>
> (you'll need to modify the function prototype to return the pointer).
> You can then drop the comment. You will also to add error handling to
> this function, as the reference will be released by
> unicam_node_release(), which is called only after successful
> registration of the video device. All error paths before registration
> will thus need to release the reference (possibly with a goto
> err_unicam_put)..
>
> > +     node->registered = true;
> > +
> > +     ret = media_create_pad_link(&unicam->sd.entity,
> > +                                 node->src_pad_id,
>
> unicam->sd is the unicam sd, node->src_pad_id is documented as being the
> source pad of the sensor. This is wrong.
>
> > +                                 &node->video_dev.entity,
> > +                                 0,
> > +                                 MEDIA_LNK_FL_ENABLED |
> > +                                 MEDIA_LNK_FL_IMMUTABLE);
> > +     if (ret)
> > +             dev_err(unicam->v4l2_dev.dev, "Unable to create pad link for %s",
> > +                     unicam->sensor->name);
>
>                 return ret;
>         }
>
> > +
> > +     unicam_mc_set_default_format(node);
>
> Call this before registering the video device, otherwise it can race
> with userspace.
>
> > +
> > +     return ret;
>
>         return 0;
>
> > +}
> > +
> > +static void unregister_nodes(struct unicam_device *unicam)
> > +{
> > +     unsigned int i;
> > +
> > +     for (i = 0; i < ARRAY_SIZE(unicam->node); i++) {
> > +             struct unicam_node *node = &unicam->node[i];
> > +
> > +             if (node->dummy_buf_cpu_addr) {
> > +                     dma_free_coherent(&unicam->pdev->dev, DUMMY_BUF_SIZE,
> > +                                       node->dummy_buf_cpu_addr,
> > +                                       node->dummy_buf_dma_addr);
> > +             }
>
> No need for curly braces.
>
> > +
> > +             if (node->registered) {
> > +                     node->registered = false;
> > +                     video_unregister_device(&node->video_dev);
>
> Swap the two lines.
>
> > +             }
> > +     }
> > +}
> > +
> > +static int unicam_async_complete(struct v4l2_async_notifier *notifier)
> > +{
> > +     struct unicam_device *unicam = to_unicam_device(notifier->v4l2_dev);
> > +     unsigned int i, source_pads = 0;
> > +     int ret;
> > +     static struct lock_class_key key;
> > +
> > +     unicam->v4l2_dev.notify = unicam_notify;
> > +
> > +     unicam->sensor_state = __v4l2_subdev_state_alloc(unicam->sensor,
> > +                                                      "unicam:state->lock",
> > +                                                      &key);
>
> You never use sensor_state.
>
> > +     if (!unicam->sensor_state)
> > +             return -ENOMEM;
> > +
> > +     for (i = 0; i < unicam->sd.entity.num_pads; i++) {
> > +             if (unicam->sd.entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) {
> > +                     if (source_pads < MAX_NODES) {
> > +                             unicam->node[source_pads].src_pad_id = i;
> > +                             dev_dbg(unicam->v4l2_dev.dev, "source pad %u is index %u\n",
> > +                                     source_pads, i);
> > +                     }
> > +                     source_pads++;
> > +             }
> > +     }
> > +     if (!source_pads) {
> > +             dev_err(unicam->v4l2_dev.dev, "No source pads on sensor.\n");
> > +             goto unregister;
> > +     }
>
> You're not looking at the sensor here, unicam->sd is the unicam subdev.
> Furthermore, you're hardcoding the source pad of the sensor to 0 below
> when creating the link. And in any case, that's not how it's supposed to
> be done, a source subdev could have multiple source pads, you need to
> identify the correct one from the device tree.
>
> The right way to handle this is to replace the call to
> media_create_pad_link() with v4l2_create_fwnode_links_to_pad(). This can
> be done in the .bound() handler.
>
> > +
> > +     ret = register_node(unicam, &unicam->node[IMAGE_NODE],
> > +                         V4L2_BUF_TYPE_VIDEO_CAPTURE);
>
> Replace the type parameter with a enum unicam_node_type, so this will
> become
>
>         ret = register_node(unicam, &unicam->node[IMAGE_NODE], IMAGE_NODE);
>
> which is less error-prone. You could even drop the second parameters:
>
>         ret = register_node(unicam, IMAGE_NODE);
>
> > +     if (ret) {
> > +             dev_err(unicam->v4l2_dev.dev, "Unable to register image video device.\n");
> > +             goto unregister;
> > +     }
> > +
> > +     /* \todo: check before :-) */
> > +     unicam->sensor_embedded_data = true;
>
> Check what ? In any case I don't think this belongs here.
>
> > +
> > +     ret = register_node(unicam, &unicam->node[METADATA_NODE],
> > +                         V4L2_BUF_TYPE_META_CAPTURE);
> > +     if (ret) {
> > +             dev_err(unicam->v4l2_dev.dev, "Unable to register metadata video device.\n");
> > +             goto unregister;
> > +     }
> > +
> > +     ret = media_create_pad_link(&unicam->sensor->entity,
> > +                                 0,
> > +                                 &unicam->sd.entity,
> > +                                 UNICAM_SD_PAD_SINK,
> > +                                 MEDIA_LNK_FL_ENABLED |
> > +                                 MEDIA_LNK_FL_IMMUTABLE);
> > +     if (ret)
> > +             dev_err(unicam->v4l2_dev.dev, "Unable to create pad link for %s",
> > +                     unicam->sensor->name);
> > +
> > +     ret = v4l2_device_register_subdev_nodes(&unicam->v4l2_dev);
> > +     if (ret) {
> > +             dev_err(unicam->v4l2_dev.dev, "Unable to register subdev nodes.\n");
> > +             goto unregister;
> > +     }
> > +
> > +     /*
> > +      * Release the initial reference, all references are now owned by the
> > +      * video devices.
> > +      */
> > +     unicam_put(unicam);
> > +     return 0;
> > +
> > +unregister:
> > +     unregister_nodes(unicam);
> > +     unicam_put(unicam);
> > +
> > +     return ret;
> > +}
> > +
> > +static const struct v4l2_async_notifier_operations unicam_async_ops = {
> > +     .bound = unicam_async_bound,
> > +     .complete = unicam_async_complete,
> > +};
> > +
> > +static int of_unicam_connect_subdevs(struct unicam_device *dev)
> > +{
> > +     struct platform_device *pdev = dev->pdev;
> > +     struct v4l2_fwnode_endpoint ep = { };
> > +     struct device_node *ep_node;
> > +     struct device_node *sensor_node;
> > +     unsigned int lane;
> > +     int ret = -EINVAL;
> > +
> > +     if (of_property_read_u32(pdev->dev.of_node, "num-data-lanes",
> > +                              &dev->max_data_lanes) < 0) {
> > +             dev_err(dev->v4l2_dev.dev, "number of data lanes not set\n");
> > +             return -EINVAL;
> > +     }
> > +
> > +     /* Get the local endpoint and remote device. */
> > +     ep_node = of_graph_get_next_endpoint(pdev->dev.of_node, NULL);
>
> Use of_graph_get_endpoint_by_regs(node, 0, -1).
>
> > +     if (!ep_node) {
> > +             dev_dbg(dev->v4l2_dev.dev, "can't get next endpoint\n");
>
>                 dev_dbg(dev->v4l2_dev.dev, "No endpoint\n");
>
> > +             return -EINVAL;
> > +     }
> > +
> > +     dev_dbg(dev->v4l2_dev.dev, "ep_node is %pOF\n", ep_node);
>
> You can drop this.
>
> > +
> > +     sensor_node = of_graph_get_remote_port_parent(ep_node);
> > +     if (!sensor_node) {
> > +             dev_dbg(dev->v4l2_dev.dev, "can't get remote parent\n");
> > +             goto cleanup_exit;
> > +     }
> > +
> > +     dev_dbg(dev->v4l2_dev.dev, "found subdevice %pOF\n", sensor_node);
>
> There's no subdev yet, we're dealing with DT here.
>
>         dev_dbg(dev->v4l2_dev.dev, "found source device %pOF\n", sensor_node);
>
> But I would actually drop all this. The sensor_node is only used in
> debug or error messages, so you could remove it and use ep_node in those
> messages instead. Or even better, drop the "subdevice %pOF: " prefix in
> the messages, that will make the code simpler.
>
> > +
> > +     /* Parse the local endpoint and validate its configuration. */
> > +     v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), &ep);
>
> Use v4l2_fwnode_endpoint_alloc_parse() and check for errors (and update
> the error cleanup path accordingly).
>
> > +
> > +     dev_dbg(dev->v4l2_dev.dev, "parsed local endpoint, bus_type %u\n",
> > +             ep.bus_type);
> > +
> > +     dev->bus_type = ep.bus_type;
> > +
> > +     switch (ep.bus_type) {
> > +     case V4L2_MBUS_CSI2_DPHY:
> > +             switch (ep.bus.mipi_csi2.num_data_lanes) {
> > +             case 1:
> > +             case 2:
> > +             case 4:
> > +                     break;
> > +
> > +             default:
> > +                     dev_err(dev->v4l2_dev.dev, "subdevice %pOF: %u data lanes not supported\n",
> > +                             sensor_node,
> > +                             ep.bus.mipi_csi2.num_data_lanes);
> > +                     goto cleanup_exit;
> > +             }
> > +
> > +             for (lane = 0; lane < ep.bus.mipi_csi2.num_data_lanes; lane++) {
> > +                     if (ep.bus.mipi_csi2.data_lanes[lane] != lane + 1) {
> > +                             dev_err(dev->v4l2_dev.dev, "subdevice %pOF: data lanes reordering not supported\n",
> > +                                     sensor_node);
> > +                             goto cleanup_exit;
> > +                     }
> > +             }
> > +
> > +             if (ep.bus.mipi_csi2.num_data_lanes > dev->max_data_lanes) {
> > +                     dev_err(dev->v4l2_dev.dev, "subdevice requires %u data lanes when %u are supported\n",
>
> s/subdevice/endpoint/
>
> > +                             ep.bus.mipi_csi2.num_data_lanes,
> > +                             dev->max_data_lanes);
> > +             }
> > +
> > +             dev->max_data_lanes = ep.bus.mipi_csi2.num_data_lanes;
> > +             dev->bus_flags = ep.bus.mipi_csi2.flags;
> > +
> > +             break;
> > +
> > +     case V4L2_MBUS_CCP2:
> > +             if (ep.bus.mipi_csi1.clock_lane != 0 ||
> > +                 ep.bus.mipi_csi1.data_lane != 1) {
> > +                     dev_err(dev->v4l2_dev.dev, "subdevice %pOF: unsupported lanes configuration\n",
> > +                             sensor_node);
> > +                     goto cleanup_exit;
> > +             }
> > +
> > +             dev->max_data_lanes = 1;
> > +             dev->bus_flags = ep.bus.mipi_csi1.strobe;
> > +             break;
>
> I wonder if this driver will ever be used with a CCP2 sensor.

Quite probably not. Are there any still available?
I do recall someone trying to hook a TI SN65LVDS315 parallel to CSI1 /
CCP converter to a Pi, but don't recall whether they managed it.

> > +
> > +     default:
> > +             /* Unsupported bus type */
> > +             dev_err(dev->v4l2_dev.dev, "subdevice %pOF: unsupported bus type %u\n",
> > +                     sensor_node, ep.bus_type);
> > +             goto cleanup_exit;
> > +     }
> > +
> > +     dev_dbg(dev->v4l2_dev.dev, "subdevice %pOF: %s bus, %u data lanes, flags=0x%08x\n",
> > +             sensor_node,
> > +             dev->bus_type == V4L2_MBUS_CSI2_DPHY ? "CSI-2" : "CCP2",
> > +             dev->max_data_lanes, dev->bus_flags);
> > +
> > +     /* Initialize and register the async notifier. */
> > +     v4l2_async_nf_init(&dev->notifier);
> > +     dev->notifier.ops = &unicam_async_ops;
> > +
> > +     dev->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
> > +     dev->asd.match.fwnode = fwnode_graph_get_remote_endpoint(of_fwnode_handle(ep_node));
> > +     ret = v4l2_async_nf_add_subdev(&dev->notifier, &dev->asd);
>
> The asd must be dynamically allocated as stated by the documentation of
> __v4l2_async_nf_add_subdev(). You can use
> v4l2_async_nf_add_fwnode_remote() to simplify this.
>
> > +     if (ret) {
> > +             dev_err(dev->v4l2_dev.dev, "Error adding subdevice: %d\n", ret);
> > +             goto cleanup_exit;
> > +     }
> > +
> > +     ret = v4l2_async_nf_register(&dev->v4l2_dev, &dev->notifier);
> > +     if (ret) {
> > +             dev_err(dev->v4l2_dev.dev, "Error registering async notifier: %d\n", ret);
> > +             ret = -EINVAL;
> > +     }
> > +
> > +cleanup_exit:
> > +     of_node_put(sensor_node);
> > +     of_node_put(ep_node);
> > +
> > +     return ret;
> > +}
> > +
> > +static int bcm2835_media_dev_init(struct unicam_device *unicam,
> > +                               struct platform_device *pdev)
> > +{
> > +     int ret = 0;
> > +
> > +     unicam->mdev.dev = &pdev->dev;
> > +     strscpy(unicam->mdev.model, UNICAM_MODULE_NAME,
> > +             sizeof(unicam->mdev.model));
> > +     strscpy(unicam->mdev.serial, "", sizeof(unicam->mdev.serial));
> > +     snprintf(unicam->mdev.bus_info, sizeof(unicam->mdev.bus_info),
> > +              "platform:%s", dev_name(&pdev->dev));
> > +     unicam->mdev.hw_revision = 0;
> > +
> > +     media_device_init(&unicam->mdev);
> > +
> > +     unicam->v4l2_dev.mdev = &unicam->mdev;
> > +
> > +     ret = v4l2_device_register(&pdev->dev, &unicam->v4l2_dev);
>
>         return v4l2_device_register(&pdev->dev, &unicam->v4l2_dev);
>
> > +
> > +     return ret;
> > +}
> > +
> > +/* Internal subdev */
> > +
> > +static int _unicam_subdev_set_routing(struct v4l2_subdev *sd,
>
> __ is more conventional.
>
> > +                                   struct v4l2_subdev_state *state,
> > +                                   struct v4l2_subdev_krouting *routing)
> > +{
> > +     static const struct v4l2_mbus_framefmt format = {
> > +             .width = 640,
> > +             .height = 480,
> > +             .code = MEDIA_BUS_FMT_UYVY8_2X8,
> > +             .field = V4L2_FIELD_NONE,
> > +             .colorspace = V4L2_COLORSPACE_SRGB,
> > +             .ycbcr_enc = V4L2_YCBCR_ENC_601,
> > +             .quantization = V4L2_QUANTIZATION_LIM_RANGE,
> > +             .xfer_func = V4L2_XFER_FUNC_SRGB,
> > +             .flags = 0,
> > +     };
>
> As this should match the values in unicam_mc_set_default_format(), can
> you move this structure out of the function, and use it to initialize
> the pix_fmt fields in unicam_mc_set_default_format() ?
>
> > +     int ret;
> > +
> > +     ret = v4l2_subdev_routing_validate_1_to_1(routing);
> > +     if (ret)
> > +             return ret;
> > +
> > +     v4l2_subdev_lock_state(state);
> > +
> > +     ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format);
> > +
> > +     v4l2_subdev_unlock_state(state);
> > +
> > +     if (ret)
> > +             return ret;
> > +
> > +     return 0;
> > +}
> > +
> > +static int unicam_subdev_set_routing(struct v4l2_subdev *sd,
> > +                                  struct v4l2_subdev_state *state,
> > +                                  enum v4l2_subdev_format_whence which,
> > +                                  struct v4l2_subdev_krouting *routing)
> > +{
> > +     struct unicam_device *unicam = sd_to_unicam_device(sd);
> > +
> > +     if (which == V4L2_SUBDEV_FORMAT_ACTIVE && unicam->streaming)
> > +             return -EBUSY;
> > +
> > +     return _unicam_subdev_set_routing(sd, state, routing);
> > +}
> > +
> > +static int unicam_subdev_init_cfg(struct v4l2_subdev *sd,
> > +                               struct v4l2_subdev_state *state)
> > +{
> > +     struct v4l2_subdev_route routes[] = {
> > +             {
> > +                     .sink_pad = 0,
> > +                     .sink_stream = 0,
> > +                     .source_pad = 1,
>
> You have macros you can use for the pad numbers.
>
> > +                     .source_stream = 0,
> > +                     .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
> > +             },
> > +     };
> > +
> > +     struct v4l2_subdev_krouting routing = {
> > +             .num_routes = ARRAY_SIZE(routes),
> > +             .routes = routes,
> > +     };
> > +
> > +     /* Initialize routing to single route to the fist source pad */
> > +     return _unicam_subdev_set_routing(sd, state, &routing);
> > +}
> > +
> > +static int unicam_subdev_enum_mbus_code(struct v4l2_subdev *sd,
> > +                                     struct v4l2_subdev_state *state,
> > +                                     struct v4l2_subdev_mbus_code_enum *code)
> > +{
> > +     int ret = 0;
> > +
> > +     v4l2_subdev_lock_state(state);
> > +
> > +     /* No transcoding, source and sink codes must match. */
> > +     if (unicam_sd_pad_is_source(code->pad)) {
> > +             struct v4l2_mbus_framefmt *fmt;
> > +
> > +             if (code->index > 0) {
> > +                     ret = -EINVAL;
> > +                     goto out;
> > +             }
> > +
> > +             fmt = v4l2_subdev_state_get_opposite_stream_format(state,
> > +                                                                code->pad,
> > +                                                                code->stream);
> > +             if (!fmt) {
> > +                     ret = -EINVAL;
> > +                     goto out;
> > +             }
> > +
> > +             code->code = fmt->code;
> > +     } else {
> > +             if (code->index >= ARRAY_SIZE(formats)) {
> > +                     ret = -EINVAL;
> > +                     goto out;
> > +             }
> > +
> > +             code->code = formats[code->index].code;
> > +     }
> > +
> > +out:
> > +     v4l2_subdev_unlock_state(state);
> > +
> > +     return ret;
> > +}
> > +
> > +static int unicam_subdev_start_streaming(struct unicam_device *unicam)
> > +{
> > +     const struct v4l2_subdev_krouting *routing;
> > +     struct v4l2_subdev_state *state;
> > +     int ret = 0;
>
> No need to initialize ret to 0.
>
> > +
> > +     state = v4l2_subdev_lock_active_state(&unicam->sd);
> > +
> > +     routing = &state->routing;
> > +
> > +     v4l2_subdev_unlock_state(state);
>
> As a piece of conceptual art, maybe, but as useful code, I have some
> doubts.
>
> > +
> > +     unicam->streaming = true;
> > +
> > +     ret = v4l2_subdev_call(unicam->sensor, video, s_stream, 1);
> > +     if (ret) {
> > +             v4l2_subdev_call(unicam->sensor, video, s_stream, 0);
>
> If .s_stream(1) fails, why do you need to call .s_stream(0) ?
>
> > +             unicam->streaming = false;
>
> Drop this, and move the unicam->streaming = true line below.
>
> > +             return ret;
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static int unicam_subdev_stop_streaming(struct unicam_device *unicam)
> > +{
> > +     v4l2_subdev_call(unicam->sensor, video, s_stream, 0);
> > +
> > +     unicam->streaming = false;
> > +
> > +     return 0;
> > +}
> > +
> > +static int unicam_subdev_s_stream(struct v4l2_subdev *sd, int enable)
> > +{
> > +     struct unicam_device *unicam = sd_to_unicam_device(sd);
> > +
> > +     if (enable)
> > +             return unicam_subdev_start_streaming(unicam);
> > +     else
> > +             return unicam_subdev_stop_streaming(unicam);
> > +     return 0;
>
> Drop the last line.
>
> > +}
> > +
> > +static int unicam_subdev_set_pad_format(struct v4l2_subdev *sd,
> > +                                     struct v4l2_subdev_state *state,
> > +                                     struct v4l2_subdev_format *format)
> > +{
> > +     struct unicam_device *unicam = sd_to_unicam_device(sd);
> > +     struct v4l2_mbus_framefmt *fmt;
> > +     int ret = 0;
> > +
> > +     if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE && unicam->streaming)
> > +             return -EBUSY;
> > +
> > +     /* No transcoding, source and sink formats must match. */
> > +     if (unicam_sd_pad_is_source(format->pad))
> > +             return v4l2_subdev_get_fmt(sd, state, format);
> > +
> > +     // TODO: implement fmt validation
>
> That's a candidate for v3.
>
> > +
> > +     v4l2_subdev_lock_state(state);
> > +
> > +     fmt = v4l2_state_get_stream_format(state, format->pad, format->stream);
> > +     if (!fmt) {
> > +             ret = -EINVAL;
> > +             goto out;
> > +     }
> > +
> > +     *fmt = format->format;
> > +
> > +     fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad,
> > +                                                        format->stream);
> > +     if (!fmt) {
> > +             ret = -EINVAL;
> > +             goto out;
> > +     }
> > +
> > +     *fmt = format->format;
>
> Let's avoid applying the format on one pad to then fail on the other
> pad.
>
>         sink_format = v4l2_state_get_stream_format(state, format->pad,
>                                                    format->stream);
>         source_format = v4l2_subdev_state_get_opposite_stream_format(state,
>                                                                      format->pad,
>                                                                      format->stream);
>         if (!sink_format || !source_format) {
>                 ret = -EINVAL;
>                 goto out;
>         }
>
>         *sink_format = format->format;
>         *source_format = format->format;
>
> > +
> > +out:
> > +     v4l2_subdev_unlock_state(state);
> > +
> > +     return ret;
> > +}
> > +
> > +static int unicam_subdev_enum_frame_size(struct v4l2_subdev *sd,
> > +                                      struct v4l2_subdev_state *state,
> > +                                      struct v4l2_subdev_frame_size_enum *fse)
> > +{
> > +     const struct unicam_fmt *fmtinfo;
> > +     int ret = 0;
> > +
> > +     if (fse->index > 0)
> > +             return -EINVAL;
> > +
> > +     v4l2_subdev_lock_state(state);
> > +
> > +     /* No transcoding, source and sink formats must match. */
> > +     if (unicam_sd_pad_is_source(fse->pad)) {
> > +             struct v4l2_mbus_framefmt *fmt;
> > +
> > +             fmt = v4l2_subdev_state_get_opposite_stream_format(state,
> > +                                                                fse->pad,
> > +                                                                fse->stream);
> > +
>
> You can drop this blank line.
>
> > +             if (!fmt) {
> > +                     ret = -EINVAL;
> > +                     goto out;
> > +             }
> > +
> > +             if (fse->code != fmt->code) {
> > +                     ret = -EINVAL;
> > +                     goto out;
> > +             }
> > +
> > +             fse->min_width = fmt->width;
> > +             fse->max_width = fmt->width;
> > +             fse->min_height = fmt->height;
> > +             fse->max_height = fmt->height;
> > +     } else {
> > +             fmtinfo = find_format_by_code(fse->code);
> > +             if (!fmtinfo) {
> > +                     ret = -EINVAL;
> > +                     goto out;
> > +             }
> > +
> > +             fse->min_width = MIN_WIDTH * 8 / ALIGN(fmtinfo->depth, 8);
> > +             fse->max_width = MAX_WIDTH * 8 / ALIGN(fmtinfo->depth, 8);
> > +             fse->min_height = MIN_HEIGHT;
> > +             fse->max_height = MAX_HEIGHT;
> > +     }
> > +
> > +out:
> > +     v4l2_subdev_unlock_state(state);
> > +
> > +     return ret;
> > +}
> > +
> > +static const struct v4l2_subdev_video_ops unicam_subdev_video_ops = {
> > +     .s_stream       = unicam_subdev_s_stream,
> > +};
> > +
> > +static const struct v4l2_subdev_pad_ops unicam_subdev_pad_ops = {
> > +     .init_cfg               = unicam_subdev_init_cfg,
> > +     .enum_mbus_code         = unicam_subdev_enum_mbus_code,
> > +     .get_fmt                = v4l2_subdev_get_fmt,
> > +     .set_fmt                = unicam_subdev_set_pad_format,
> > +     .set_routing            = unicam_subdev_set_routing,
> > +     .enum_frame_size        = unicam_subdev_enum_frame_size,
> > +};
> > +
> > +static const struct v4l2_subdev_ops unicam_subdev_ops = {
> > +     .video          = &unicam_subdev_video_ops,
> > +     .pad            = &unicam_subdev_pad_ops,
> > +};
> > +
> > +static struct media_entity_operations unicam_subdev_media_ops = {
>
> static const
>
> > +     .link_validate = v4l2_subdev_link_validate,
> > +     .has_route = v4l2_subdev_has_route,
> > +};
> > +
> > +static int unicam_probe(struct platform_device *pdev)
> > +{
> > +     struct unicam_device *unicam;
> > +     int ret = 0;
> > +     int i;
> > +
> > +     unicam = kzalloc(sizeof(*unicam), GFP_KERNEL);
> > +     if (!unicam)
> > +             return -ENOMEM;
> > +
> > +     kref_init(&unicam->kref);
> > +     unicam->pdev = pdev;
> > +
> > +     unicam->base = devm_platform_ioremap_resource(pdev, 0);
> > +     if (IS_ERR(unicam->base)) {
> > +             dev_err(unicam->v4l2_dev.dev, "Failed to get main io block\n");
>
> Let's use unicam->dev to access the struct device, especially given that
> unicam->v4l2_dev is only initialized below when calling
> bcm2835_media_dev_init().
>
> This message can actually br dropped, devm_platform_ioremap_resource()
> already prints an error.
>
> > +             ret = PTR_ERR(unicam->base);
> > +             goto err_unicam_put;
> > +     }
> > +
> > +     unicam->clk_gate_base = devm_platform_ioremap_resource(pdev, 1);
> > +     if (IS_ERR(unicam->clk_gate_base)) {
> > +             dev_err(unicam->v4l2_dev.dev, "Failed to get 2nd io block\n");
>
> Same here.
>
> > +             ret = PTR_ERR(unicam->clk_gate_base);
> > +             goto err_unicam_put;
> > +     }
> > +
> > +     unicam->clock = devm_clk_get(&pdev->dev, "lp");
> > +     if (IS_ERR(unicam->clock)) {
> > +             dev_err(unicam->v4l2_dev.dev, "Failed to get lp clock\n");
> > +             ret = PTR_ERR(unicam->clock);
> > +             goto err_unicam_put;
> > +     }
> > +
> > +     unicam->vpu_clock = devm_clk_get(&pdev->dev, "vpu");
> > +     if (IS_ERR(unicam->vpu_clock)) {
> > +             dev_err(unicam->v4l2_dev.dev, "Failed to get vpu clock\n");
> > +             ret = PTR_ERR(unicam->vpu_clock);
> > +             goto err_unicam_put;
> > +     }
>
> Could the clock bulk API help here ?
>
> > +
> > +     ret = platform_get_irq(pdev, 0);
> > +     if (ret <= 0) {
> > +             dev_err(&pdev->dev, "No IRQ resource\n");
> > +             ret = -EINVAL;
> > +             goto err_unicam_put;
> > +     }
> > +
> > +     ret = devm_request_irq(&pdev->dev, ret, unicam_isr, 0,
> > +                            "unicam_capture0", unicam);
> > +     if (ret) {
> > +             dev_err(&pdev->dev, "Unable to request interrupt\n");
> > +             ret = -EINVAL;
> > +             goto err_unicam_put;
> > +     }
> > +
> > +     ret = bcm2835_media_dev_init(unicam, pdev);
> > +     if (ret) {
> > +             dev_err(unicam->v4l2_dev.dev,
> > +                     "Unable to register v4l2 device.\n");
> > +             goto err_unicam_put;
> > +     }
> > +
> > +     ret = media_device_register(&unicam->mdev);
> > +     if (ret < 0) {
> > +             dev_err(unicam->v4l2_dev.dev,
> > +                     "Unable to register media-controller device.\n");
> > +             goto err_v4l2_unregister;
> > +     }
> > +
> > +     /* Reserve space for the controls */
> > +     ret = v4l2_ctrl_handler_init(&unicam->ctrl_handler, 16);
> > +     if (ret < 0)
> > +             goto err_media_unregister;
>
> The control handler is unused, drop it.
>
> > +
> > +     /* set the driver data in platform device */
> > +     platform_set_drvdata(pdev, unicam);
> > +
> > +     dev_dbg(unicam->v4l2_dev.dev, "Initialize internal subdev");
>
> You can drop this.
>
> > +     v4l2_subdev_init(&unicam->sd, &unicam_subdev_ops);
> > +     v4l2_set_subdevdata(&unicam->sd, unicam);
> > +     unicam->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
> > +     unicam->sd.dev = &pdev->dev;
> > +     unicam->sd.owner = THIS_MODULE;
> > +     unicam->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_MULTIPLEXED;
> > +     snprintf(unicam->sd.name, sizeof(unicam->sd.name), "unicam-subdev");
> > +
> > +     unicam->pads[UNICAM_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
> > +
> > +     for (i = UNICAM_SD_PAD_FIRST_SOURCE; i < UNICAM_SD_NUM_PADS; ++i)
> > +             unicam->pads[i].flags = MEDIA_PAD_FL_SOURCE;
>
>         unicam->pads[UNICAM_SD_PAD_SOURCE_IMAGE].flags = MEDIA_PAD_FL_SOURCE;
>         unicam->pads[UNICAM_SD_PAD_SOURCE_META].flags = MEDIA_PAD_FL_SOURCE;
>
> > +     unicam->sd.entity.ops = &unicam_subdev_media_ops;
> > +     ret = media_entity_pads_init(&unicam->sd.entity,
> > +                                  ARRAY_SIZE(unicam->pads), unicam->pads);
> > +     if (ret) {
> > +             dev_err(unicam->v4l2_dev.dev, "Could not init media controller for subdev");
> > +             goto err_subdev_unregister;
> > +     }
> > +
> > +     ret = v4l2_subdev_init_finalize(&unicam->sd);
> > +     if (ret) {
> > +             dev_err(unicam->v4l2_dev.dev, "Could not finalize init for subdev");
> > +             goto err_entity_cleanup;
> > +     }
> > +
> > +     ret = v4l2_device_register_subdev(&unicam->v4l2_dev, &unicam->sd);
> > +     if (ret) {
> > +             dev_err(&pdev->dev, "Failed to register internal subdev\n");
> > +             goto err_subdev_unregister;
> > +     }
>
> Let's split initialization and registration of the subdev to a separate
> function, placed above with the subdev operations.
>
> > +
> > +     ret = of_unicam_connect_subdevs(unicam);
> > +     if (ret) {
> > +             dev_err(&pdev->dev, "Failed to connect subdevs\n");
> > +             goto err_subdev_unregister;
> > +     }
> > +
> > +     /* Enable the block power domain */
> > +     pm_runtime_enable(&pdev->dev);
> > +
> > +     return 0;
> > +
> > +err_subdev_unregister:
> > +     v4l2_subdev_cleanup(&unicam->sd);
> > +err_entity_cleanup:
> > +     media_entity_cleanup(&unicam->sd.entity);
> > +err_media_unregister:
> > +     media_device_unregister(&unicam->mdev);
> > +err_v4l2_unregister:
> > +     v4l2_device_unregister(&unicam->v4l2_dev);
> > +err_unicam_put:
> > +     unicam_put(unicam);
> > +
> > +     return ret;
> > +}
> > +
> > +static int unicam_remove(struct platform_device *pdev)
> > +{
> > +     struct unicam_device *unicam = platform_get_drvdata(pdev);
> > +
> > +     v4l2_async_nf_unregister(&unicam->notifier);
> > +     v4l2_device_unregister(&unicam->v4l2_dev);
> > +     media_device_unregister(&unicam->mdev);
> > +     unregister_nodes(unicam);
>
> I'm a bit worried there could be race conditions with userspace here.
> For instance, calling v4l2_async_nf_unregister() will result in
> v4l2_device_unregister_subdev() being called on the sensor subdev, which
> may race with userspace starting capture on a video node. The following
> order would, I think be safer:
>
>         unregister_nodes(unicam);
>         v4l2_device_unregister(&unicam->v4l2_dev);
>         media_device_unregister(&unicam->mdev);
>         v4l2_async_nf_unregister(&unicam->notifier);
>
> But this will cause a problem, when unregistering device nodes, the last
> reference to unicam would be dropped. I think you could drop the calls
> to unicam_put() from unicam_async_complete(), and add a unicam_put()
> call here. Dave, does that sound good to you ?

That sounds sane to me.

  Dave

> > +
> > +     pm_runtime_disable(&pdev->dev);
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct of_device_id unicam_of_match[] = {
> > +     { .compatible = "brcm,bcm2835-unicam", },
> > +     { /* sentinel */ },
> > +};
> > +MODULE_DEVICE_TABLE(of, unicam_of_match);
> > +
> > +static struct platform_driver unicam_driver = {
> > +     .probe          = unicam_probe,
> > +     .remove         = unicam_remove,
> > +     .driver = {
> > +             .name   = UNICAM_MODULE_NAME,
> > +             .of_match_table = of_match_ptr(unicam_of_match),
> > +     },
> > +};
> > +
> > +module_platform_driver(unicam_driver);
> > +
> > +MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com>");
> > +MODULE_DESCRIPTION("BCM2835 Unicam driver");
> > +MODULE_LICENSE("GPL");
> > +MODULE_VERSION(UNICAM_VERSION);
> > diff --git a/drivers/media/platform/bcm2835/vc4-regs-unicam.h b/drivers/media/platform/bcm2835/vc4-regs-unicam.h
> > new file mode 100644
> > index 000000000000..ae059a171d0f
> > --- /dev/null
> > +++ b/drivers/media/platform/bcm2835/vc4-regs-unicam.h
> > @@ -0,0 +1,253 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +
> > +/*
> > + * Copyright (C) 2017-2020 Raspberry Pi Trading.
> > + * Dave Stevenson <dave.stevenson@raspberrypi.com>
> > + */
> > +
> > +#ifndef VC4_REGS_UNICAM_H
> > +#define VC4_REGS_UNICAM_H
> > +
> > +/*
> > + * The following values are taken from files found within the code drop
> > + * made by Broadcom for the BCM21553 Graphics Driver, predominantly in
> > + * brcm_usrlib/dag/vmcsx/vcinclude/hardware_vc4.h.
> > + * They have been modified to be only the register offset.
> > + */
> > +#define UNICAM_CTRL  0x000
> > +#define UNICAM_STA   0x004
> > +#define UNICAM_ANA   0x008
> > +#define UNICAM_PRI   0x00c
> > +#define UNICAM_CLK   0x010
> > +#define UNICAM_CLT   0x014
> > +#define UNICAM_DAT0  0x018
> > +#define UNICAM_DAT1  0x01c
> > +#define UNICAM_DAT2  0x020
> > +#define UNICAM_DAT3  0x024
> > +#define UNICAM_DLT   0x028
> > +#define UNICAM_CMP0  0x02c
> > +#define UNICAM_CMP1  0x030
> > +#define UNICAM_CAP0  0x034
> > +#define UNICAM_CAP1  0x038
> > +#define UNICAM_ICTL  0x100
> > +#define UNICAM_ISTA  0x104
> > +#define UNICAM_IDI0  0x108
> > +#define UNICAM_IPIPE 0x10c
> > +#define UNICAM_IBSA0 0x110
> > +#define UNICAM_IBEA0 0x114
> > +#define UNICAM_IBLS  0x118
> > +#define UNICAM_IBWP  0x11c
> > +#define UNICAM_IHWIN 0x120
> > +#define UNICAM_IHSTA 0x124
> > +#define UNICAM_IVWIN 0x128
> > +#define UNICAM_IVSTA 0x12c
> > +#define UNICAM_ICC   0x130
> > +#define UNICAM_ICS   0x134
> > +#define UNICAM_IDC   0x138
> > +#define UNICAM_IDPO  0x13c
> > +#define UNICAM_IDCA  0x140
> > +#define UNICAM_IDCD  0x144
> > +#define UNICAM_IDS   0x148
> > +#define UNICAM_DCS   0x200
> > +#define UNICAM_DBSA0 0x204
> > +#define UNICAM_DBEA0 0x208
> > +#define UNICAM_DBWP  0x20c
> > +#define UNICAM_DBCTL 0x300
> > +#define UNICAM_IBSA1 0x304
> > +#define UNICAM_IBEA1 0x308
> > +#define UNICAM_IDI1  0x30c
> > +#define UNICAM_DBSA1 0x310
> > +#define UNICAM_DBEA1 0x314
> > +#define UNICAM_MISC  0x400
>
> Please add one tab before the value, to match the indentation of the
> rest of the file.
>
> > +
> > +/*
> > + * The following bitmasks are from the kernel released by Broadcom
> > + * for Android - https://android.googlesource.com/kernel/bcm/
> > + * The Rhea, Hawaii, and Java chips all contain the same VideoCore4
> > + * Unicam block as BCM2835, as defined in eg
> > + * arch/arm/mach-rhea/include/mach/rdb_A0/brcm_rdb_cam.h and similar.
> > + * Values reworked to use the kernel BIT and GENMASK macros.
> > + *
> > + * Some of the bit mnenomics have been amended to match the datasheet.
> > + */
> > +/* UNICAM_CTRL Register */
> > +#define UNICAM_CPE           BIT(0)
> > +#define UNICAM_MEM           BIT(1)
> > +#define UNICAM_CPR           BIT(2)
> > +#define UNICAM_CPM_MASK              GENMASK(3, 3)
> > +#define UNICAM_CPM_CSI2              0
> > +#define UNICAM_CPM_CCP2              1
> > +#define UNICAM_SOE           BIT(4)
> > +#define UNICAM_DCM_MASK              GENMASK(5, 5)
> > +#define UNICAM_DCM_STROBE    0
> > +#define UNICAM_DCM_DATA              1
> > +#define UNICAM_SLS           BIT(6)
> > +#define UNICAM_PFT_MASK              GENMASK(11, 8)
> > +#define UNICAM_OET_MASK              GENMASK(20, 12)
> > +
> > +/* UNICAM_STA Register */
> > +#define UNICAM_SYN           BIT(0)
> > +#define UNICAM_CS            BIT(1)
> > +#define UNICAM_SBE           BIT(2)
> > +#define UNICAM_PBE           BIT(3)
> > +#define UNICAM_HOE           BIT(4)
> > +#define UNICAM_PLE           BIT(5)
> > +#define UNICAM_SSC           BIT(6)
> > +#define UNICAM_CRCE          BIT(7)
> > +#define UNICAM_OES           BIT(8)
> > +#define UNICAM_IFO           BIT(9)
> > +#define UNICAM_OFO           BIT(10)
> > +#define UNICAM_BFO           BIT(11)
> > +#define UNICAM_DL            BIT(12)
> > +#define UNICAM_PS            BIT(13)
> > +#define UNICAM_IS            BIT(14)
> > +#define UNICAM_PI0           BIT(15)
> > +#define UNICAM_PI1           BIT(16)
> > +#define UNICAM_FSI_S         BIT(17)
> > +#define UNICAM_FEI_S         BIT(18)
> > +#define UNICAM_LCI_S         BIT(19)
> > +#define UNICAM_BUF0_RDY              BIT(20)
> > +#define UNICAM_BUF0_NO               BIT(21)
> > +#define UNICAM_BUF1_RDY              BIT(22)
> > +#define UNICAM_BUF1_NO               BIT(23)
> > +#define UNICAM_DI            BIT(24)
> > +
> > +#define UNICAM_STA_MASK_ALL \
> > +             (UNICAM_DL + \
> > +             UNICAM_SBE + \
> > +             UNICAM_PBE + \
> > +             UNICAM_HOE + \
> > +             UNICAM_PLE + \
> > +             UNICAM_SSC + \
> > +             UNICAM_CRCE + \
> > +             UNICAM_IFO + \
> > +             UNICAM_OFO + \
> > +             UNICAM_PS + \
> > +             UNICAM_PI0 + \
> > +             UNICAM_PI1)
>
> I'd use | instead of + to combine bits. Same below.
>
> > +
> > +/* UNICAM_ANA Register */
> > +#define UNICAM_APD           BIT(0)
> > +#define UNICAM_BPD           BIT(1)
> > +#define UNICAM_AR            BIT(2)
> > +#define UNICAM_DDL           BIT(3)
> > +#define UNICAM_CTATADJ_MASK  GENMASK(7, 4)
> > +#define UNICAM_PTATADJ_MASK  GENMASK(11, 8)
> > +
> > +/* UNICAM_PRI Register */
> > +#define UNICAM_PE            BIT(0)
> > +#define UNICAM_PT_MASK               GENMASK(2, 1)
> > +#define UNICAM_NP_MASK               GENMASK(7, 4)
> > +#define UNICAM_PP_MASK               GENMASK(11, 8)
> > +#define UNICAM_BS_MASK               GENMASK(15, 12)
> > +#define UNICAM_BL_MASK               GENMASK(17, 16)
> > +
> > +/* UNICAM_CLK Register */
> > +#define UNICAM_CLE           BIT(0)
> > +#define UNICAM_CLPD          BIT(1)
> > +#define UNICAM_CLLPE         BIT(2)
> > +#define UNICAM_CLHSE         BIT(3)
> > +#define UNICAM_CLTRE         BIT(4)
> > +#define UNICAM_CLAC_MASK     GENMASK(8, 5)
> > +#define UNICAM_CLSTE         BIT(29)
> > +
> > +/* UNICAM_CLT Register */
> > +#define UNICAM_CLT1_MASK     GENMASK(7, 0)
> > +#define UNICAM_CLT2_MASK     GENMASK(15, 8)
> > +
> > +/* UNICAM_DATn Registers */
> > +#define UNICAM_DLE           BIT(0)
> > +#define UNICAM_DLPD          BIT(1)
> > +#define UNICAM_DLLPE         BIT(2)
> > +#define UNICAM_DLHSE         BIT(3)
> > +#define UNICAM_DLTRE         BIT(4)
> > +#define UNICAM_DLSM          BIT(5)
> > +#define UNICAM_DLFO          BIT(28)
> > +#define UNICAM_DLSTE         BIT(29)
> > +
> > +#define UNICAM_DAT_MASK_ALL (UNICAM_DLSTE + UNICAM_DLFO)
>
> This also needs an indentation fix, as well as UNICAM_ISTA_MASK_ALL.
>
> > +
> > +/* UNICAM_DLT Register */
> > +#define UNICAM_DLT1_MASK     GENMASK(7, 0)
> > +#define UNICAM_DLT2_MASK     GENMASK(15, 8)
> > +#define UNICAM_DLT3_MASK     GENMASK(23, 16)
> > +
> > +/* UNICAM_ICTL Register */
> > +#define UNICAM_FSIE          BIT(0)
> > +#define UNICAM_FEIE          BIT(1)
> > +#define UNICAM_IBOB          BIT(2)
> > +#define UNICAM_FCM           BIT(3)
> > +#define UNICAM_TFC           BIT(4)
> > +#define UNICAM_LIP_MASK              GENMASK(6, 5)
> > +#define UNICAM_LCIE_MASK     GENMASK(28, 16)
> > +
> > +/* UNICAM_IDI0/1 Register */
> > +#define UNICAM_ID0_MASK              GENMASK(7, 0)
> > +#define UNICAM_ID1_MASK              GENMASK(15, 8)
> > +#define UNICAM_ID2_MASK              GENMASK(23, 16)
> > +#define UNICAM_ID3_MASK              GENMASK(31, 24)
> > +
> > +/* UNICAM_ISTA Register */
> > +#define UNICAM_FSI           BIT(0)
> > +#define UNICAM_FEI           BIT(1)
> > +#define UNICAM_LCI           BIT(2)
> > +
> > +#define UNICAM_ISTA_MASK_ALL (UNICAM_FSI + UNICAM_FEI + UNICAM_LCI)
> > +
> > +/* UNICAM_IPIPE Register */
> > +#define UNICAM_PUM_MASK              GENMASK(2, 0)
> > +             /* Unpacking modes */
> > +             #define UNICAM_PUM_NONE         0
> > +             #define UNICAM_PUM_UNPACK6      1
> > +             #define UNICAM_PUM_UNPACK7      2
> > +             #define UNICAM_PUM_UNPACK8      3
> > +             #define UNICAM_PUM_UNPACK10     4
> > +             #define UNICAM_PUM_UNPACK12     5
> > +             #define UNICAM_PUM_UNPACK14     6
> > +             #define UNICAM_PUM_UNPACK16     7
> > +#define UNICAM_DDM_MASK              GENMASK(6, 3)
> > +#define UNICAM_PPM_MASK              GENMASK(9, 7)
> > +             /* Packing modes */
> > +             #define UNICAM_PPM_NONE         0
> > +             #define UNICAM_PPM_PACK8        1
> > +             #define UNICAM_PPM_PACK10       2
> > +             #define UNICAM_PPM_PACK12       3
> > +             #define UNICAM_PPM_PACK14       4
> > +             #define UNICAM_PPM_PACK16       5
>
> I'd drop the leading tab.
>
> > +#define UNICAM_DEM_MASK              GENMASK(11, 10)
> > +#define UNICAM_DEBL_MASK     GENMASK(14, 12)
> > +#define UNICAM_ICM_MASK              GENMASK(16, 15)
> > +#define UNICAM_IDM_MASK              GENMASK(17, 17)
> > +
> > +/* UNICAM_ICC Register */
> > +#define UNICAM_ICFL_MASK     GENMASK(4, 0)
> > +#define UNICAM_ICFH_MASK     GENMASK(9, 5)
> > +#define UNICAM_ICST_MASK     GENMASK(12, 10)
> > +#define UNICAM_ICLT_MASK     GENMASK(15, 13)
> > +#define UNICAM_ICLL_MASK     GENMASK(31, 16)
> > +
> > +/* UNICAM_DCS Register */
> > +#define UNICAM_DIE           BIT(0)
> > +#define UNICAM_DIM           BIT(1)
> > +#define UNICAM_DBOB          BIT(3)
> > +#define UNICAM_FDE           BIT(4)
> > +#define UNICAM_LDP           BIT(5)
> > +#define UNICAM_EDL_MASK              GENMASK(15, 8)
> > +
> > +/* UNICAM_DBCTL Register */
> > +#define UNICAM_DBEN          BIT(0)
> > +#define UNICAM_BUF0_IE               BIT(1)
> > +#define UNICAM_BUF1_IE               BIT(2)
> > +
> > +/* UNICAM_CMP[0,1] register */
> > +#define UNICAM_PCE           BIT(31)
> > +#define UNICAM_GI            BIT(9)
> > +#define UNICAM_CPH           BIT(8)
> > +#define UNICAM_PCVC_MASK     GENMASK(7, 6)
> > +#define UNICAM_PCDT_MASK     GENMASK(5, 0)
> > +
> > +/* UNICAM_MISC register */
> > +#define UNICAM_FL0           BIT(6)
> > +#define UNICAM_FL1           BIT(9)
> > +
> > +#endif
>
> --
> Regards,
>
> Laurent Pinchart

^ permalink raw reply

* Re: [PATCH V1 3/6] iio: accel: sca3300: modified to support multi chips
From: kernel test robot @ 2022-01-24 15:32 UTC (permalink / raw)
  To: LI Qingwu, jic23, lars, robh+dt, tomas.melin, andy.shevchenko,
	devicetree, linux-kernel
  Cc: kbuild-all, LI Qingwu
In-Reply-To: <20220124093912.2429190-4-Qing-wu.Li@leica-geosystems.com.cn>

Hi LI,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on jic23-iio/togreg]
[also build test WARNING on v5.17-rc1 next-20220124]
[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/LI-Qingwu/i-iio-accel-sca3300-add-compitible-for-scl3300/20220124-174021
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
config: parisc-randconfig-r015-20220124 (https://download.01.org/0day-ci/archive/20220124/202201242336.1dSTFe7a-lkp@intel.com/config)
compiler: hppa-linux-gcc (GCC) 11.2.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/7dc3bc68cdfcb252dd79fea28a5e944d76784fe8
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review LI-Qingwu/i-iio-accel-sca3300-add-compitible-for-scl3300/20220124-174021
        git checkout 7dc3bc68cdfcb252dd79fea28a5e944d76784fe8
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=parisc SHELL=/bin/bash drivers/iio/accel/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/iio/accel/sca3300.c:74:60: error: macro "IIO_ENUM_AVAILABLE" requires 3 arguments, but only 2 given
      74 |         IIO_ENUM_AVAILABLE("op_mode", &sca3300_op_mode_enum),
         |                                                            ^
   In file included from include/linux/iio/buffer.h:10,
                    from drivers/iio/accel/sca3300.c:17:
   include/linux/iio/iio.h:112: note: macro "IIO_ENUM_AVAILABLE" defined here
     112 | #define IIO_ENUM_AVAILABLE(_name, _shared, _e) \
         | 
   drivers/iio/accel/sca3300.c:74:9: error: 'IIO_ENUM_AVAILABLE' undeclared here (not in a function)
      74 |         IIO_ENUM_AVAILABLE("op_mode", &sca3300_op_mode_enum),
         |         ^~~~~~~~~~~~~~~~~~
>> drivers/iio/accel/sca3300.c:185:31: warning: initialization of 'long unsigned int' from 'const long unsigned int *' makes integer from pointer without a cast [-Wint-conversion]
     185 |                 .scan_masks = sca3300_scan_masks,
         |                               ^~~~~~~~~~~~~~~~~~
   drivers/iio/accel/sca3300.c:185:31: note: (near initialization for 'sca3300_chip_info_tbl[0].scan_masks')
   drivers/iio/accel/sca3300.c: In function 'sca3300_write_raw':
>> drivers/iio/accel/sca3300.c:307:34: warning: comparison between pointer and integer
     307 |                         if ((val == sca3300_accel_scale[data->chip_info->chip_type][0]) &&
         |                                  ^~
   drivers/iio/accel/sca3300.c:308:35: warning: comparison between pointer and integer
     308 |                             (val2 == sca3300_accel_scale[data->chip_info->chip_type][1]))
         |                                   ^~
   drivers/iio/accel/sca3300.c: In function 'sca3300_init':
>> drivers/iio/accel/sca3300.c:422:57: warning: assignment to 'const long unsigned int *' from 'long unsigned int' makes pointer from integer without a cast [-Wint-conversion]
     422 |                         indio_dev->available_scan_masks = sca3300_chip_info_tbl[i].scan_masks;
         |                                                         ^


vim +185 drivers/iio/accel/sca3300.c

   177	
   178	static const struct sca3300_chip_info sca3300_chip_info_tbl[] = {
   179		[CHIP_SCA3300] = {
   180			.chip_type = CHIP_SCA3300,
   181			.name = "sca3300",
   182			.chip_id = 0x51,
   183			.channels = sca3300_channels,
   184			.num_channels = ARRAY_SIZE(sca3300_channels),
 > 185			.scan_masks = sca3300_scan_masks,
   186		},
   187	};
   188	
   189	DECLARE_CRC8_TABLE(sca3300_crc_table);
   190	
   191	static int sca3300_transfer(struct sca3300_data *sca_data, int *val)
   192	{
   193		/* Consecutive requests min. 10 us delay (Datasheet section 5.1.2) */
   194		struct spi_delay delay = { .value = 10, .unit = SPI_DELAY_UNIT_USECS };
   195		int32_t ret;
   196		int rs;
   197		u8 crc;
   198		struct spi_transfer xfers[2] = {
   199			{
   200				.tx_buf = sca_data->txbuf,
   201				.len = ARRAY_SIZE(sca_data->txbuf),
   202				.delay = delay,
   203				.cs_change = 1,
   204			},
   205			{
   206				.rx_buf = sca_data->rxbuf,
   207				.len = ARRAY_SIZE(sca_data->rxbuf),
   208				.delay = delay,
   209			}
   210		};
   211	
   212		/* inverted crc value as described in device data sheet */
   213		crc = ~crc8(sca3300_crc_table, &sca_data->txbuf[0], 3, CRC8_INIT_VALUE);
   214		sca_data->txbuf[3] = crc;
   215	
   216		ret = spi_sync_transfer(sca_data->spi, xfers, ARRAY_SIZE(xfers));
   217		if (ret) {
   218			dev_err(&sca_data->spi->dev,
   219				"transfer error, error: %d\n", ret);
   220			return -EIO;
   221		}
   222	
   223		crc = ~crc8(sca3300_crc_table, &sca_data->rxbuf[0], 3, CRC8_INIT_VALUE);
   224		if (sca_data->rxbuf[3] != crc) {
   225			dev_err(&sca_data->spi->dev, "CRC checksum mismatch");
   226			return -EIO;
   227		}
   228	
   229		/* get return status */
   230		rs = sca_data->rxbuf[0] & SCA3300_MASK_RS_STATUS;
   231		if (rs == SCA3300_VALUE_RS_ERROR)
   232			ret = -EINVAL;
   233	
   234		*val = sign_extend32(get_unaligned_be16(&sca_data->rxbuf[1]), 15);
   235	
   236		return ret;
   237	}
   238	
   239	static int sca3300_error_handler(struct sca3300_data *sca_data)
   240	{
   241		int ret;
   242		int val;
   243	
   244		mutex_lock(&sca_data->lock);
   245		sca_data->txbuf[0] = SCA3300_REG_STATUS << 2;
   246		ret = sca3300_transfer(sca_data, &val);
   247		mutex_unlock(&sca_data->lock);
   248		/*
   249		 * Return status error is cleared after reading status register once,
   250		 * expect EINVAL here.
   251		 */
   252		if (ret != -EINVAL) {
   253			dev_err(&sca_data->spi->dev,
   254				"error reading device status: %d\n", ret);
   255			return ret;
   256		}
   257	
   258		dev_err(&sca_data->spi->dev, "device status: 0x%lx\n",
   259			val & SCA3300_STATUS_MASK);
   260	
   261		return 0;
   262	}
   263	
   264	static int sca3300_read_reg(struct sca3300_data *sca_data, u8 reg, int *val)
   265	{
   266		int ret;
   267	
   268		mutex_lock(&sca_data->lock);
   269		sca_data->txbuf[0] = reg << 2;
   270		ret = sca3300_transfer(sca_data, val);
   271		mutex_unlock(&sca_data->lock);
   272		if (ret != -EINVAL)
   273			return ret;
   274	
   275		return sca3300_error_handler(sca_data);
   276	}
   277	
   278	static int sca3300_write_reg(struct sca3300_data *sca_data, u8 reg, int val)
   279	{
   280		int reg_val = 0;
   281		int ret;
   282	
   283		mutex_lock(&sca_data->lock);
   284		/* BIT(7) for write operation */
   285		sca_data->txbuf[0] = BIT(7) | (reg << 2);
   286		put_unaligned_be16(val, &sca_data->txbuf[1]);
   287		ret = sca3300_transfer(sca_data, &reg_val);
   288		mutex_unlock(&sca_data->lock);
   289		if (ret != -EINVAL)
   290			return ret;
   291	
   292		return sca3300_error_handler(sca_data);
   293	}
   294	
   295	static int sca3300_write_raw(struct iio_dev *indio_dev,
   296				     struct iio_chan_spec const *chan,
   297				     int val, int val2, long mask)
   298	{
   299		struct sca3300_data *data = iio_priv(indio_dev);
   300		int reg_val;
   301		int ret;
   302		int i;
   303	
   304		switch (mask) {
   305		case IIO_CHAN_INFO_SCALE:
   306			for (i = 0; i < OP_MOD_CNT; i++) {
 > 307				if ((val == sca3300_accel_scale[data->chip_info->chip_type][0]) &&
   308				    (val2 == sca3300_accel_scale[data->chip_info->chip_type][1]))
   309					return sca3300_write_reg(data, SCA3300_REG_MODE, i);
   310			}
   311			return -EINVAL;
   312		case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
   313			ret = sca3300_read_reg(data, SCA3300_REG_MODE, &reg_val);
   314			if (ret)
   315				return ret;
   316			/* freq. change is possible only for mode 3 and 4 */
   317			if (reg_val == 2 && val == sca3300_lp_freq[data->chip_info->chip_type][3])
   318				return sca3300_write_reg(data, SCA3300_REG_MODE, 3);
   319			if (reg_val == 3 && val == sca3300_lp_freq[data->chip_info->chip_type][2])
   320				return sca3300_write_reg(data, SCA3300_REG_MODE, 2);
   321			return -EINVAL;
   322		default:
   323			return -EINVAL;
   324		}
   325	}
   326	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

^ permalink raw reply

* Re: [PATCH v4 2/2] clk: qcom: Add display clock controller driver for QCM2290
From: Loic Poulain @ 2022-01-24 15:39 UTC (permalink / raw)
  To: bjorn.andersson
  Cc: linux-arm-msm, shawn.guo, robh+dt, agross, linux-clk, devicetree,
	sboyd
In-Reply-To: <1639763060-24524-2-git-send-email-loic.poulain@linaro.org>

Hi Bjorn,

On Fri, 17 Dec 2021 at 18:32, Loic Poulain <loic.poulain@linaro.org> wrote:
>
> Add support for the display clock controller found in QCM2290
> based devices. This clock controller feeds the Multimedia Display
> SubSystem (MDSS).
>
> It's a porting of dispcc-scuba GPL-2.0 driver from CAF msm-4.19 kernel:
> https://source.codeaurora.org/quic/la/kernel/msm-4.19/tree/drivers/clk/qcom/dispcc-scuba.c?h=LE.UM.4.4.1.r3
>
> Global clock name references (parent_names) have been replaced by
> parent_data and parent_hws.
>
> Clocks marked enable_safe_config have their clk_rcg2_ops moved to
> clk_rcg2_shared_ops.
>
> Signed-off-by: Loic Poulain <loic.poulain@linaro.org>

Any other comments on this series?

Regards,
Loic

> ---
>  v2: Added missing dispcc-qcm2290.h header file
>  v3: - Moved dt-bindings header into dt bindings commit
>      - clk_rcg2_ops to clk_rcg2_shared_ops for enable_safe_config
>        marked clocks.
>  v4: - Removed useless NOCACHE clk flags
>      - Added explicit comment for OPS_PARENT_ENABLE flag
>      - Removed useless headers (clk.h, reset.h)
>      - spark_vco tab as const
>      - removed global .name reference for sleep_clk
>      - removed dispcc_xo_clk as it is always on (enabled in probe)
>      - removed dev_info message on probe success
>      - Kconfig: Select QCM_GCC_2290 for builtin

^ permalink raw reply

* Re: [PATCH v2 0/7] usb: dwc3: Calculate REFCLKPER et. al. from reference clock
From: Kathiravan Thirumoorthy @ 2022-01-24 15:11 UTC (permalink / raw)
  To: Baruch Siach, Kathiravan T
  Cc: Sean Anderson, Greg Kroah-Hartman, linux-usb, Felipe Balbi,
	Thinh Nguyen, Balaji Prakash J, linux-kernel, Robert Hancock,
	Andy Gross, Bjorn Andersson, Michal Simek, Rob Herring,
	devicetree, linux-arm-kernel, linux-arm-msm
In-Reply-To: <871r12g0j2.fsf@tarshish>

Hi Baruch,

On 1/20/2022 3:59 PM, Baruch Siach wrote:
> Hi Kathiravan,
>
> On Thu, Jan 20 2022, Kathiravan T wrote:
>> On 2022-01-19 23:44, Baruch Siach wrote:
>>> Hi Sean,
>>> On Tue, Jan 18 2022, Sean Anderson wrote:
>>>> This is a rework of patches 3-5 of [1]. It attempts to correctly program
>>>> REFCLKPER and REFCLK_FLADJ based on the reference clock frequency. Since
>>>> we no longer need a special property duplicating this configuration,
>>>> snps,ref-clock-period-ns is deprecated.
>>>> Please test this! Patches 3/4 in this series have the effect of
>>>> programming REFCLKPER and REFCLK_FLADJ on boards which already configure
>>>> the "ref" clock. I have build tested, but not much else.
>>> Tested here on IPQ6010 based system. USB still works. But the with
>>> "ref"
>>> clock at 24MHz, period is calculated as 0x29. Previous
>>> snps,ref-clock-period-ns value used to be 0x32.
>>> Is that expected?
>> Yes, it is 0x29 for IPQ60xx based SoCs. In downstream it was wrongly mentioned
>> as 0x32, which was corrected recently.
> Thanks for the update. This needs fixing in upstream kernel. I'll send a
> patch.
>
> For some reason USB appears to work here with both values. Is it because
> I only use USB2 signals? If this is the case them I can not actually
> test this series on my system.

I could recollect we did see some issue on USB2.0 port as well, but it 
wasn't fatal one. Anyways it is better to test it.

Thanks,

Kathiravan T.

>
> Thanks,
> baruch
>
>>>> [1]
>>>> https://lore.kernel.org/linux-usb/20220114044230.2677283-1-robert.hancock@calian.com/
>>>> Changes in v2:
>>>> - Document clock members
>>>> - Also program GFLADJ.240MHZDECR
>>>> - Don't program GFLADJ if the version is < 2.50a
>>>> - Add snps,ref-clock-frequency-hz property for ACPI
>>>> Sean Anderson (7):
>>>>    dt-bindings: usb: dwc3: Deprecate snps,ref-clock-period-ns
>>>>    usb: dwc3: Get clocks individually
>>>>    usb: dwc3: Calculate REFCLKPER based on reference clock
>>>>    usb: dwc3: Program GFLADJ
>>>>    usb: dwc3: Add snps,ref-clock-frequency-hz property for ACPI
>>>>    arm64: dts: zynqmp: Move USB clocks to dwc3 node
>>>>    arm64: dts: ipq6018: Use reference clock to set dwc3 period
>>>>   .../devicetree/bindings/usb/snps,dwc3.yaml    |   7 +-
>>>>   arch/arm64/boot/dts/qcom/ipq6018.dtsi         |   3 +-
>>>>   .../arm64/boot/dts/xilinx/zynqmp-clk-ccf.dtsi |   4 +-
>>>>   arch/arm64/boot/dts/xilinx/zynqmp.dtsi        |   4 +-
>>>>   drivers/usb/dwc3/core.c                       | 112 +++++++++++++++---
>>>>   drivers/usb/dwc3/core.h                       |  17 ++-
>>>>   6 files changed, 120 insertions(+), 27 deletions(-)
>

^ permalink raw reply

* [PATCH v3] arm64: dts: qcom: ipq8074: add the reserved-memory node
From: Kathiravan T @ 2022-01-24 15:05 UTC (permalink / raw)
  To: agross, bjorn.andersson, robh+dt, linux-arm-msm, devicetree,
	linux-kernel
  Cc: Kathiravan T

4MB of memory is needed for TZ. So mark that region as reserved
appropriately.

Signed-off-by: Kathiravan T <quic_kathirav@quicinc.com>
---
Changes since v2:
	* Rebased on top of v5.17-rc1
	* Reworded the commit message and title
Changes since v1:
        * Fixed the commit title

 arch/arm64/boot/dts/qcom/ipq8074.dtsi | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/ipq8074.dtsi b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
index e6cc261201ef..26ba7ce9222c 100644
--- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi
@@ -82,6 +82,17 @@
 		};
 	};
 
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		memory@4ac00000 {
+			no-map;
+			reg = <0x0 0x4ac00000 0x0 0x00400000>;
+		};
+	};
+
 	soc: soc {
 		#address-cells = <0x1>;
 		#size-cells = <0x1>;
-- 
2.7.4


^ permalink raw reply related

* Re: [PATCH V1 3/6] iio: accel: sca3300: modified to support multi chips
From: kernel test robot @ 2022-01-24 15:01 UTC (permalink / raw)
  To: LI Qingwu, jic23, lars, robh+dt, tomas.melin, andy.shevchenko,
	devicetree, linux-kernel
  Cc: llvm, kbuild-all, LI Qingwu
In-Reply-To: <20220124093912.2429190-4-Qing-wu.Li@leica-geosystems.com.cn>

Hi LI,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on jic23-iio/togreg]
[also build test WARNING on v5.17-rc1 next-20220124]
[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/LI-Qingwu/i-iio-accel-sca3300-add-compitible-for-scl3300/20220124-174021
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git togreg
config: hexagon-randconfig-r033-20220124 (https://download.01.org/0day-ci/archive/20220124/202201242207.0V8eUHu2-lkp@intel.com/config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project 2e58a18910867ba6795066e044293e6daf89edf5)
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/7dc3bc68cdfcb252dd79fea28a5e944d76784fe8
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review LI-Qingwu/i-iio-accel-sca3300-add-compitible-for-scl3300/20220124-174021
        git checkout 7dc3bc68cdfcb252dd79fea28a5e944d76784fe8
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash drivers/iio/accel/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/iio/accel/sca3300.c:74:53: error: too few arguments provided to function-like macro invocation
           IIO_ENUM_AVAILABLE("op_mode", &sca3300_op_mode_enum),
                                                              ^
   include/linux/iio/iio.h:112:9: note: macro 'IIO_ENUM_AVAILABLE' defined here
   #define IIO_ENUM_AVAILABLE(_name, _shared, _e) \
           ^
   drivers/iio/accel/sca3300.c:74:2: error: use of undeclared identifier 'IIO_ENUM_AVAILABLE'
           IIO_ENUM_AVAILABLE("op_mode", &sca3300_op_mode_enum),
           ^
>> drivers/iio/accel/sca3300.c:185:17: warning: incompatible pointer to integer conversion initializing 'unsigned long' with an expression of type 'const unsigned long[2]' [-Wint-conversion]
                   .scan_masks = sca3300_scan_masks,
                                 ^~~~~~~~~~~~~~~~~~
>> drivers/iio/accel/sca3300.c:307:13: warning: comparison between pointer and integer ('int' and 'const int *') [-Wpointer-integer-compare]
                           if ((val == sca3300_accel_scale[data->chip_info->chip_type][0]) &&
                                ~~~ ^  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/iio/accel/sca3300.c:308:14: warning: comparison between pointer and integer ('int' and 'const int *') [-Wpointer-integer-compare]
                               (val2 == sca3300_accel_scale[data->chip_info->chip_type][1]))
                                ~~~~ ^  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/iio/accel/sca3300.c:422:36: warning: incompatible integer to pointer conversion assigning to 'const unsigned long *' from 'const unsigned long'; take the address with & [-Wint-conversion]
                           indio_dev->available_scan_masks = sca3300_chip_info_tbl[i].scan_masks;
                                                           ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                             &
   4 warnings and 2 errors generated.


vim +185 drivers/iio/accel/sca3300.c

   177	
   178	static const struct sca3300_chip_info sca3300_chip_info_tbl[] = {
   179		[CHIP_SCA3300] = {
   180			.chip_type = CHIP_SCA3300,
   181			.name = "sca3300",
   182			.chip_id = 0x51,
   183			.channels = sca3300_channels,
   184			.num_channels = ARRAY_SIZE(sca3300_channels),
 > 185			.scan_masks = sca3300_scan_masks,
   186		},
   187	};
   188	
   189	DECLARE_CRC8_TABLE(sca3300_crc_table);
   190	
   191	static int sca3300_transfer(struct sca3300_data *sca_data, int *val)
   192	{
   193		/* Consecutive requests min. 10 us delay (Datasheet section 5.1.2) */
   194		struct spi_delay delay = { .value = 10, .unit = SPI_DELAY_UNIT_USECS };
   195		int32_t ret;
   196		int rs;
   197		u8 crc;
   198		struct spi_transfer xfers[2] = {
   199			{
   200				.tx_buf = sca_data->txbuf,
   201				.len = ARRAY_SIZE(sca_data->txbuf),
   202				.delay = delay,
   203				.cs_change = 1,
   204			},
   205			{
   206				.rx_buf = sca_data->rxbuf,
   207				.len = ARRAY_SIZE(sca_data->rxbuf),
   208				.delay = delay,
   209			}
   210		};
   211	
   212		/* inverted crc value as described in device data sheet */
   213		crc = ~crc8(sca3300_crc_table, &sca_data->txbuf[0], 3, CRC8_INIT_VALUE);
   214		sca_data->txbuf[3] = crc;
   215	
   216		ret = spi_sync_transfer(sca_data->spi, xfers, ARRAY_SIZE(xfers));
   217		if (ret) {
   218			dev_err(&sca_data->spi->dev,
   219				"transfer error, error: %d\n", ret);
   220			return -EIO;
   221		}
   222	
   223		crc = ~crc8(sca3300_crc_table, &sca_data->rxbuf[0], 3, CRC8_INIT_VALUE);
   224		if (sca_data->rxbuf[3] != crc) {
   225			dev_err(&sca_data->spi->dev, "CRC checksum mismatch");
   226			return -EIO;
   227		}
   228	
   229		/* get return status */
   230		rs = sca_data->rxbuf[0] & SCA3300_MASK_RS_STATUS;
   231		if (rs == SCA3300_VALUE_RS_ERROR)
   232			ret = -EINVAL;
   233	
   234		*val = sign_extend32(get_unaligned_be16(&sca_data->rxbuf[1]), 15);
   235	
   236		return ret;
   237	}
   238	
   239	static int sca3300_error_handler(struct sca3300_data *sca_data)
   240	{
   241		int ret;
   242		int val;
   243	
   244		mutex_lock(&sca_data->lock);
   245		sca_data->txbuf[0] = SCA3300_REG_STATUS << 2;
   246		ret = sca3300_transfer(sca_data, &val);
   247		mutex_unlock(&sca_data->lock);
   248		/*
   249		 * Return status error is cleared after reading status register once,
   250		 * expect EINVAL here.
   251		 */
   252		if (ret != -EINVAL) {
   253			dev_err(&sca_data->spi->dev,
   254				"error reading device status: %d\n", ret);
   255			return ret;
   256		}
   257	
   258		dev_err(&sca_data->spi->dev, "device status: 0x%lx\n",
   259			val & SCA3300_STATUS_MASK);
   260	
   261		return 0;
   262	}
   263	
   264	static int sca3300_read_reg(struct sca3300_data *sca_data, u8 reg, int *val)
   265	{
   266		int ret;
   267	
   268		mutex_lock(&sca_data->lock);
   269		sca_data->txbuf[0] = reg << 2;
   270		ret = sca3300_transfer(sca_data, val);
   271		mutex_unlock(&sca_data->lock);
   272		if (ret != -EINVAL)
   273			return ret;
   274	
   275		return sca3300_error_handler(sca_data);
   276	}
   277	
   278	static int sca3300_write_reg(struct sca3300_data *sca_data, u8 reg, int val)
   279	{
   280		int reg_val = 0;
   281		int ret;
   282	
   283		mutex_lock(&sca_data->lock);
   284		/* BIT(7) for write operation */
   285		sca_data->txbuf[0] = BIT(7) | (reg << 2);
   286		put_unaligned_be16(val, &sca_data->txbuf[1]);
   287		ret = sca3300_transfer(sca_data, &reg_val);
   288		mutex_unlock(&sca_data->lock);
   289		if (ret != -EINVAL)
   290			return ret;
   291	
   292		return sca3300_error_handler(sca_data);
   293	}
   294	
   295	static int sca3300_write_raw(struct iio_dev *indio_dev,
   296				     struct iio_chan_spec const *chan,
   297				     int val, int val2, long mask)
   298	{
   299		struct sca3300_data *data = iio_priv(indio_dev);
   300		int reg_val;
   301		int ret;
   302		int i;
   303	
   304		switch (mask) {
   305		case IIO_CHAN_INFO_SCALE:
   306			for (i = 0; i < OP_MOD_CNT; i++) {
 > 307				if ((val == sca3300_accel_scale[data->chip_info->chip_type][0]) &&
   308				    (val2 == sca3300_accel_scale[data->chip_info->chip_type][1]))
   309					return sca3300_write_reg(data, SCA3300_REG_MODE, i);
   310			}
   311			return -EINVAL;
   312		case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
   313			ret = sca3300_read_reg(data, SCA3300_REG_MODE, &reg_val);
   314			if (ret)
   315				return ret;
   316			/* freq. change is possible only for mode 3 and 4 */
   317			if (reg_val == 2 && val == sca3300_lp_freq[data->chip_info->chip_type][3])
   318				return sca3300_write_reg(data, SCA3300_REG_MODE, 3);
   319			if (reg_val == 3 && val == sca3300_lp_freq[data->chip_info->chip_type][2])
   320				return sca3300_write_reg(data, SCA3300_REG_MODE, 2);
   321			return -EINVAL;
   322		default:
   323			return -EINVAL;
   324		}
   325	}
   326	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

^ permalink raw reply

* Re: [PATCH] arm64: dts: qcom: Fix msm8998 cache nodes
From: Rob Herring @ 2022-01-24 14:53 UTC (permalink / raw)
  To: Andy Gross, Bjorn Andersson; +Cc: linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <20211217211136.3536443-1-robh@kernel.org>

On Fri, Dec 17, 2021 at 3:11 PM Rob Herring <robh@kernel.org> wrote:
>
> The msm8998 cache nodes have some issues. First, L1 caches are described
> within cpu nodes, not as separate nodes. The 'next-level-cache' property
> is of course in the correct location, otherwise the cache hierarchy
> walking would not work. Remove all the L1 cache nodes.
>
> Second, 'arm,arch-cache' is not a documented compatible string. "cache"
> is a sufficient compatible string for the Arm architected caches.
>
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
>  arch/arm64/boot/dts/qcom/msm8998.dtsi | 52 ++-------------------------
>  1 file changed, 2 insertions(+), 50 deletions(-)

Ping

>
> diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> index 408f265e277b..00adee461b52 100644
> --- a/arch/arm64/boot/dts/qcom/msm8998.dtsi
> +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi
> @@ -138,15 +138,9 @@ CPU0: cpu@0 {
>                         cpu-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>;
>                         next-level-cache = <&L2_0>;
>                         L2_0: l2-cache {
> -                               compatible = "arm,arch-cache";
> +                               compatible = "cache";
>                                 cache-level = <2>;
>                         };
> -                       L1_I_0: l1-icache {
> -                               compatible = "arm,arch-cache";
> -                       };
> -                       L1_D_0: l1-dcache {
> -                               compatible = "arm,arch-cache";
> -                       };
>                 };
>
>                 CPU1: cpu@1 {
> @@ -157,12 +151,6 @@ CPU1: cpu@1 {
>                         capacity-dmips-mhz = <1024>;
>                         cpu-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>;
>                         next-level-cache = <&L2_0>;
> -                       L1_I_1: l1-icache {
> -                               compatible = "arm,arch-cache";
> -                       };
> -                       L1_D_1: l1-dcache {
> -                               compatible = "arm,arch-cache";
> -                       };
>                 };
>
>                 CPU2: cpu@2 {
> @@ -173,12 +161,6 @@ CPU2: cpu@2 {
>                         capacity-dmips-mhz = <1024>;
>                         cpu-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>;
>                         next-level-cache = <&L2_0>;
> -                       L1_I_2: l1-icache {
> -                               compatible = "arm,arch-cache";
> -                       };
> -                       L1_D_2: l1-dcache {
> -                               compatible = "arm,arch-cache";
> -                       };
>                 };
>
>                 CPU3: cpu@3 {
> @@ -189,12 +171,6 @@ CPU3: cpu@3 {
>                         capacity-dmips-mhz = <1024>;
>                         cpu-idle-states = <&LITTLE_CPU_SLEEP_0 &LITTLE_CPU_SLEEP_1>;
>                         next-level-cache = <&L2_0>;
> -                       L1_I_3: l1-icache {
> -                               compatible = "arm,arch-cache";
> -                       };
> -                       L1_D_3: l1-dcache {
> -                               compatible = "arm,arch-cache";
> -                       };
>                 };
>
>                 CPU4: cpu@100 {
> @@ -206,15 +182,9 @@ CPU4: cpu@100 {
>                         cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>;
>                         next-level-cache = <&L2_1>;
>                         L2_1: l2-cache {
> -                               compatible = "arm,arch-cache";
> +                               compatible = "cache";
>                                 cache-level = <2>;
>                         };
> -                       L1_I_100: l1-icache {
> -                               compatible = "arm,arch-cache";
> -                       };
> -                       L1_D_100: l1-dcache {
> -                               compatible = "arm,arch-cache";
> -                       };
>                 };
>
>                 CPU5: cpu@101 {
> @@ -225,12 +195,6 @@ CPU5: cpu@101 {
>                         capacity-dmips-mhz = <1536>;
>                         cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>;
>                         next-level-cache = <&L2_1>;
> -                       L1_I_101: l1-icache {
> -                               compatible = "arm,arch-cache";
> -                       };
> -                       L1_D_101: l1-dcache {
> -                               compatible = "arm,arch-cache";
> -                       };
>                 };
>
>                 CPU6: cpu@102 {
> @@ -241,12 +205,6 @@ CPU6: cpu@102 {
>                         capacity-dmips-mhz = <1536>;
>                         cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>;
>                         next-level-cache = <&L2_1>;
> -                       L1_I_102: l1-icache {
> -                               compatible = "arm,arch-cache";
> -                       };
> -                       L1_D_102: l1-dcache {
> -                               compatible = "arm,arch-cache";
> -                       };
>                 };
>
>                 CPU7: cpu@103 {
> @@ -257,12 +215,6 @@ CPU7: cpu@103 {
>                         capacity-dmips-mhz = <1536>;
>                         cpu-idle-states = <&BIG_CPU_SLEEP_0 &BIG_CPU_SLEEP_1>;
>                         next-level-cache = <&L2_1>;
> -                       L1_I_103: l1-icache {
> -                               compatible = "arm,arch-cache";
> -                       };
> -                       L1_D_103: l1-dcache {
> -                               compatible = "arm,arch-cache";
> -                       };
>                 };
>
>                 cpu-map {
> --
> 2.32.0
>

^ permalink raw reply

* Re: [PATCH] arm64: dts: imx8qm: Drop CPU 'arm,armv8' compatible
From: Rob Herring @ 2022-01-24 14:53 UTC (permalink / raw)
  To: Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team
  Cc: linux-arm-kernel, devicetree, linux-kernel
In-Reply-To: <20211217173908.3201517-1-robh@kernel.org>

On Fri, Dec 17, 2021 at 11:39 AM Rob Herring <robh@kernel.org> wrote:
>
> The CPU 'arm,armv8' compatible is only for s/w models, so remove it from
> i.MX8QM CPU nodes.
>
> Cc: Shawn Guo <shawnguo@kernel.org>
> Cc: Sascha Hauer <s.hauer@pengutronix.de>
> Cc: Pengutronix Kernel Team <kernel@pengutronix.de>
> Cc: Fabio Estevam <festevam@gmail.com>
> Cc: NXP Linux Team <linux-imx@nxp.com>
> Cc: linux-arm-kernel@lists.infradead.org
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
> Note that the PMU node is also wrong as it should have separate A72 and
> A53 nodes to get uarch specific events, but that needs some GIC changes.
> ---
>  arch/arm64/boot/dts/freescale/imx8qm.dtsi | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)

Ping

>
> diff --git a/arch/arm64/boot/dts/freescale/imx8qm.dtsi b/arch/arm64/boot/dts/freescale/imx8qm.dtsi
> index aebbe2b84aa1..b13f09ca0404 100644
> --- a/arch/arm64/boot/dts/freescale/imx8qm.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx8qm.dtsi
> @@ -54,7 +54,7 @@ core1 {
>
>                 A53_0: cpu@0 {
>                         device_type = "cpu";
> -                       compatible = "arm,cortex-a53", "arm,armv8";
> +                       compatible = "arm,cortex-a53";
>                         reg = <0x0 0x0>;
>                         enable-method = "psci";
>                         next-level-cache = <&A53_L2>;
> @@ -62,7 +62,7 @@ A53_0: cpu@0 {
>
>                 A53_1: cpu@1 {
>                         device_type = "cpu";
> -                       compatible = "arm,cortex-a53", "arm,armv8";
> +                       compatible = "arm,cortex-a53";
>                         reg = <0x0 0x1>;
>                         enable-method = "psci";
>                         next-level-cache = <&A53_L2>;
> @@ -70,7 +70,7 @@ A53_1: cpu@1 {
>
>                 A53_2: cpu@2 {
>                         device_type = "cpu";
> -                       compatible = "arm,cortex-a53", "arm,armv8";
> +                       compatible = "arm,cortex-a53";
>                         reg = <0x0 0x2>;
>                         enable-method = "psci";
>                         next-level-cache = <&A53_L2>;
> @@ -78,7 +78,7 @@ A53_2: cpu@2 {
>
>                 A53_3: cpu@3 {
>                         device_type = "cpu";
> -                       compatible = "arm,cortex-a53", "arm,armv8";
> +                       compatible = "arm,cortex-a53";
>                         reg = <0x0 0x3>;
>                         enable-method = "psci";
>                         next-level-cache = <&A53_L2>;
> @@ -86,7 +86,7 @@ A53_3: cpu@3 {
>
>                 A72_0: cpu@100 {
>                         device_type = "cpu";
> -                       compatible = "arm,cortex-a72", "arm,armv8";
> +                       compatible = "arm,cortex-a72";
>                         reg = <0x0 0x100>;
>                         enable-method = "psci";
>                         next-level-cache = <&A72_L2>;
> @@ -94,7 +94,7 @@ A72_0: cpu@100 {
>
>                 A72_1: cpu@101 {
>                         device_type = "cpu";
> -                       compatible = "arm,cortex-a72", "arm,armv8";
> +                       compatible = "arm,cortex-a72";
>                         reg = <0x0 0x101>;
>                         enable-method = "psci";
>                         next-level-cache = <&A72_L2>;
> --
> 2.32.0
>

^ permalink raw reply

* Re: [PATCH 05/15] dt-bindings: mmc: sdhci-msm: Add msm8953 compatible
From: Ulf Hansson @ 2022-01-24 14:41 UTC (permalink / raw)
  To: Luca Weiss
  Cc: linux-arm-msm, ~postmarketos/upstreaming, phone-devel,
	Konrad Dybcio, Rob Herring, linux-mmc, devicetree, linux-kernel
In-Reply-To: <20220112194118.178026-6-luca@z3ntu.xyz>

On Wed, 12 Jan 2022 at 20:42, Luca Weiss <luca@z3ntu.xyz> wrote:
>
> Add msm8953 SoC specific compatible strings for qcom-sdhci controller.
>
> Signed-off-by: Luca Weiss <luca@z3ntu.xyz>
> Acked-by: Konrad Dybcio <konrad.dybcio@somainline.org>

Applied for next, thanks!

Kind regards
Uffe


> ---
>  Documentation/devicetree/bindings/mmc/sdhci-msm.txt | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
> index 50841e2843fc..a62eaade5d97 100644
> --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
> +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
> @@ -14,6 +14,7 @@ Required properties:
>         full compatible strings with SoC and version:
>                 "qcom,apq8084-sdhci", "qcom,sdhci-msm-v4"
>                 "qcom,msm8226-sdhci", "qcom,sdhci-msm-v4"
> +               "qcom,msm8953-sdhci", "qcom,sdhci-msm-v4"
>                 "qcom,msm8974-sdhci", "qcom,sdhci-msm-v4"
>                 "qcom,msm8916-sdhci", "qcom,sdhci-msm-v4"
>                 "qcom,msm8992-sdhci", "qcom,sdhci-msm-v4"
> --
> 2.34.1
>

^ permalink raw reply

* Re: [PATCH v14 0/3] mmc: Add LiteSDCard mmc driver
From: Ulf Hansson @ 2022-01-24 14:40 UTC (permalink / raw)
  To: Gabriel Somlo
  Cc: linux-kernel, robh+dt, devicetree, linux-mmc, kgugala, mholenko,
	krakoczy, mdudek, paulus, joel, shorne, geert,
	david.abdurachmanov, florent, rdunlap, andy.shevchenko, hdanton
In-Reply-To: <20220113170300.3555651-1-gsomlo@gmail.com>

On Thu, 13 Jan 2022 at 18:03, Gabriel Somlo <gsomlo@gmail.com> wrote:
>
> Add support for the LiteX SD-Card device, LiteSDCard.
>
> LiteSDCard is a simple SD-Card interface available as part of the LiteX
> environment, used with various RISC-V and other FPGA based SoCs.
>
> New in v14:
> Documentation/devicetree/bindings/mmc/litex,mmc.yaml:
>   - add missing `vmmc-supply = ...` property to example section

This v14 series applied for next, thanks!

[...]

> Gabriel Somlo (3):
>   MAINTAINERS: co-maintain LiteX platform
>   dt-bindings: mmc: Add bindings for LiteSDCard
>   mmc: Add driver for LiteX's LiteSDCard interface
>
>  .../devicetree/bindings/mmc/litex,mmc.yaml    |  78 +++
>  MAINTAINERS                                   |   9 +-
>  drivers/mmc/host/Kconfig                      |  13 +
>  drivers/mmc/host/Makefile                     |   1 +
>  drivers/mmc/host/litex_mmc.c                  | 661 ++++++++++++++++++
>  5 files changed, 760 insertions(+), 2 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/mmc/litex,mmc.yaml
>  create mode 100644 drivers/mmc/host/litex_mmc.c
>

Kind regards
Uffe

^ permalink raw reply

* [PATCH v5 15/16] arm64: dts: fsd: Add initial pinctrl support
From: Alim Akhtar @ 2022-01-24 14:16 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel
  Cc: soc, linux-clk, devicetree, olof, arnd, linus.walleij,
	catalin.marinas, robh+dt, krzysztof.kozlowski, s.nawrocki,
	linux-samsung-soc, pankaj.dubey, sboyd, Alim Akhtar, linux-fsd,
	Shashank Prashar, Aswani Reddy
In-Reply-To: <20220124141644.71052-1-alim.akhtar@samsung.com>

Add initial pin configuration nodes for FSD SoC.

Cc: linux-fsd@tesla.com
Signed-off-by: Shashank Prashar <s.prashar@samsung.com>
Signed-off-by: Aswani Reddy <aswani.reddy@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
---
 arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi | 335 +++++++++++++++++++++
 arch/arm64/boot/dts/tesla/fsd.dtsi         |  22 ++
 2 files changed, 357 insertions(+)
 create mode 100644 arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi

diff --git a/arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi b/arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi
new file mode 100644
index 000000000000..d4d0cb005712
--- /dev/null
+++ b/arch/arm64/boot/dts/tesla/fsd-pinctrl.dtsi
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Tesla Full Self-Driving SoC device tree source
+ *
+ * Copyright (c) 2017-2021 Samsung Electronics Co., Ltd.
+ *		https://www.samsung.com
+ * Copyright (c) 2017-2021 Tesla, Inc.
+ *		https://www.tesla.com
+ */
+
+#include <dt-bindings/pinctrl/samsung.h>
+
+&pinctrl_fsys0 {
+	gpf0: gpf0-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpf1: gpf1-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpf6: gpf6-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpf4: gpf4-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpf5: gpf5-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+};
+
+&pinctrl_peric {
+	gpc8: gpc8-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpf2: gpf2-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpf3: gpf3-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpd0: gpd0-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpb0: gpb0-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpb1: gpb1-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpb4: gpb4-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpb5: gpb5-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpb6: gpb6-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpb7: gpb7-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpd1: gpd1-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpd2: gpd2-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpd3: gpd3-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpg0: gpg0-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpg1: gpg1-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpg2: gpg2-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpg3: gpg3-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpg4: gpg4-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpg5: gpg5-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpg6: gpg6-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	gpg7: gpg7-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	pwm0_out: pwm0-out-pins {
+		samsung,pins = "gpb6-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV2>;
+	};
+
+	pwm1_out: pwm1-out-pins {
+		samsung,pins = "gpb6-5";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV2>;
+	};
+
+	hs_i2c0_bus: hs-i2c0-bus-pins {
+		samsung,pins = "gpb0-0", "gpb0-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	hs_i2c1_bus: hs-i2c1-bus-pins {
+		samsung,pins = "gpb0-2", "gpb0-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	hs_i2c2_bus: hs-i2c2-bus-pins {
+		samsung,pins = "gpb0-4", "gpb0-5";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	hs_i2c3_bus: hs-i2c3-bus-pins {
+		samsung,pins = "gpb0-6", "gpb0-7";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	hs_i2c4_bus: hs-i2c4-bus-pins {
+		samsung,pins = "gpb1-0", "gpb1-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	hs_i2c5_bus: hs-i2c5-bus-pins {
+		samsung,pins = "gpb1-2", "gpb1-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	hs_i2c6_bus: hs-i2c6-bus-pins {
+		samsung,pins = "gpb1-4", "gpb1-5";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	hs_i2c7_bus: hs-i2c7-bus-pins {
+		samsung,pins = "gpb1-6", "gpb1-7";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart0_data: uart0-data-pins {
+		samsung,pins = "gpb7-0", "gpb7-1";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	uart1_data: uart1-data-pins {
+		samsung,pins = "gpb7-4", "gpb7-5";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	spi0_bus: spi0-bus-pins {
+		samsung,pins = "gpb4-0", "gpb4-2", "gpb4-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	spi1_bus: spi1-bus-pins {
+		samsung,pins = "gpb4-4", "gpb4-6", "gpb4-7";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+
+	spi2_bus: spi2-bus-pins {
+		samsung,pins = "gpb5-0", "gpb5-2", "gpb5-3";
+		samsung,pin-function = <EXYNOS_PIN_FUNC_2>;
+		samsung,pin-pud = <EXYNOS_PIN_PULL_UP>;
+		samsung,pin-drv = <EXYNOS4_PIN_DRV_LV1>;
+	};
+};
+
+&pinctrl_pmu {
+	gpq0: gpq0-gpio-bank {
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+};
diff --git a/arch/arm64/boot/dts/tesla/fsd.dtsi b/arch/arm64/boot/dts/tesla/fsd.dtsi
index 25b480147541..b7f05f78c601 100644
--- a/arch/arm64/boot/dts/tesla/fsd.dtsi
+++ b/arch/arm64/boot/dts/tesla/fsd.dtsi
@@ -26,6 +26,9 @@ aliases {
 		i2c5 = &hsi2c_5;
 		i2c6 = &hsi2c_6;
 		i2c7 = &hsi2c_7;
+		pinctrl0 = &pinctrl_fsys0;
+		pinctrl1 = &pinctrl_peric;
+		pinctrl2 = &pinctrl_pmu;
 	};
 
 	cpus {
@@ -648,5 +651,24 @@ hsi2c_7: i2c@14270000 {
 			clock-names = "hsi2c";
 			status = "disabled";
 		};
+
+		pinctrl_pmu: pinctrl@114f0000 {
+			compatible = "tesla,fsd-pinctrl";
+			reg = <0x0 0x114f0000 0x0 0x1000>;
+		};
+
+		pinctrl_peric: pinctrl@141f0000 {
+			compatible = "tesla,fsd-pinctrl";
+			reg = <0x0 0x141f0000 0x0 0x1000>;
+			interrupts = <GIC_SPI 189 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		pinctrl_fsys0: pinctrl@15020000 {
+			compatible = "tesla,fsd-pinctrl";
+			reg = <0x0 0x15020000 0x0 0x1000>;
+			interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+		};
 	};
 };
+
+#include "fsd-pinctrl.dtsi"
-- 
2.25.1


^ permalink raw reply related

* [PATCH v5 16/16] arm64: defconfig: Enable Tesla FSD SoC
From: Alim Akhtar @ 2022-01-24 14:16 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel
  Cc: soc, linux-clk, devicetree, olof, arnd, linus.walleij,
	catalin.marinas, robh+dt, krzysztof.kozlowski, s.nawrocki,
	linux-samsung-soc, pankaj.dubey, sboyd, Alim Akhtar, linux-fsd
In-Reply-To: <20220124141644.71052-1-alim.akhtar@samsung.com>

This patch enables the Tesla FSD SoC in arm64 defconfig.

Cc: linux-fsd@tesla.com
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 30516dc0b70e..415fb3aca4b3 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -54,6 +54,7 @@ CONFIG_ARCH_SEATTLE=y
 CONFIG_ARCH_INTEL_SOCFPGA=y
 CONFIG_ARCH_SYNQUACER=y
 CONFIG_ARCH_TEGRA=y
+CONFIG_ARCH_TESLA_FSD=y
 CONFIG_ARCH_SPRD=y
 CONFIG_ARCH_THUNDER=y
 CONFIG_ARCH_THUNDER2=y
-- 
2.25.1


^ permalink raw reply related

* [PATCH v5 14/16] arm64: dts: fsd: Add initial device tree support
From: Alim Akhtar @ 2022-01-24 14:16 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel
  Cc: soc, linux-clk, devicetree, olof, arnd, linus.walleij,
	catalin.marinas, robh+dt, krzysztof.kozlowski, s.nawrocki,
	linux-samsung-soc, pankaj.dubey, sboyd, Alim Akhtar, linux-fsd,
	Arjun K V, Aswani Reddy, Ajay Kumar, Sriranjani P, Chandrasekar R,
	Shashank Prashar
In-Reply-To: <20220124141644.71052-1-alim.akhtar@samsung.com>

Add initial device tree support for "Full Self-Driving" (FSD) SoC
This SoC contain three clusters of four cortex-a72 CPUs and various
peripheral IPs.

Cc: linux-fsd@tesla.com
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
Signed-off-by: Arjun K V <arjun.kv@samsung.com>
Signed-off-by: Aswani Reddy <aswani.reddy@samsung.com>
Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Signed-off-by: Sriranjani P <sriranjani.p@samsung.com>
Signed-off-by: Chandrasekar R <rcsekar@samsung.com>
Signed-off-by: Shashank Prashar <s.prashar@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
---
 MAINTAINERS                           |   8 +
 arch/arm64/Kconfig.platforms          |   6 +
 arch/arm64/boot/dts/Makefile          |   1 +
 arch/arm64/boot/dts/tesla/Makefile    |   3 +
 arch/arm64/boot/dts/tesla/fsd-evb.dts |  39 ++
 arch/arm64/boot/dts/tesla/fsd.dtsi    | 652 ++++++++++++++++++++++++++
 6 files changed, 709 insertions(+)
 create mode 100644 arch/arm64/boot/dts/tesla/Makefile
 create mode 100644 arch/arm64/boot/dts/tesla/fsd-evb.dts
 create mode 100644 arch/arm64/boot/dts/tesla/fsd.dtsi

diff --git a/MAINTAINERS b/MAINTAINERS
index 89f23af16451..d97d3a5d7f39 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2753,6 +2753,14 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/media/tegra-cec.txt
 F:	drivers/media/cec/platform/tegra/
 
+ARM/TESLA FSD SoC SUPPORT
+M:	Alim Akhtar <alim.akhtar@samsung.com>
+M:	linux-fsd@tesla.com
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L:	linux-samsung-soc@vger.kernel.org
+S:	Maintained
+F:	arch/arm64/boot/dts/tesla*
+
 ARM/TETON BGA MACHINE SUPPORT
 M:	"Mark F. Brown" <mark.brown314@gmail.com>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 7d5d58800170..739254493d6a 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -268,6 +268,12 @@ config ARCH_TEGRA
 	help
 	  This enables support for the NVIDIA Tegra SoC family.
 
+config ARCH_TESLA_FSD
+	bool "ARMv8 based Tesla platform"
+	depends on ARCH_EXYNOS
+	help
+	  Support for ARMv8 based Tesla platforms.
+
 config ARCH_SPRD
 	bool "Spreadtrum SoC platform"
 	help
diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
index 639e01a4d855..1ba04e31a438 100644
--- a/arch/arm64/boot/dts/Makefile
+++ b/arch/arm64/boot/dts/Makefile
@@ -27,6 +27,7 @@ subdir-y += rockchip
 subdir-y += socionext
 subdir-y += sprd
 subdir-y += synaptics
+subdir-y += tesla
 subdir-y += ti
 subdir-y += toshiba
 subdir-y += xilinx
diff --git a/arch/arm64/boot/dts/tesla/Makefile b/arch/arm64/boot/dts/tesla/Makefile
new file mode 100644
index 000000000000..a1ee50e2fd06
--- /dev/null
+++ b/arch/arm64/boot/dts/tesla/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_ARCH_TESLA_FSD) += \
+	fsd-evb.dtb
diff --git a/arch/arm64/boot/dts/tesla/fsd-evb.dts b/arch/arm64/boot/dts/tesla/fsd-evb.dts
new file mode 100644
index 000000000000..5af560c1b5e6
--- /dev/null
+++ b/arch/arm64/boot/dts/tesla/fsd-evb.dts
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+/*
+ * Tesla FSD board device tree source
+ *
+ * Copyright (c) 2017-2021 Samsung Electronics Co., Ltd.
+ *		https://www.samsung.com
+ * Copyright (c) 2017-2021 Tesla, Inc.
+ *		https://www.tesla.com
+ */
+
+/dts-v1/;
+#include "fsd.dtsi"
+
+/ {
+	model = "Tesla Full Self-Driving (FSD) Evaluation board";
+	compatible = "tesla,fsd-evb", "tesla,fsd";
+
+	aliases {
+		serial0 = &serial_0;
+		serial1 = &serial_1;
+	};
+
+	chosen {
+		stdout-path = &serial_0;
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x0 0x80000000 0x2 0x00000000>;
+	};
+};
+
+&fin_pll {
+	clock-frequency = <24000000>;
+};
+
+&serial_0 {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/tesla/fsd.dtsi b/arch/arm64/boot/dts/tesla/fsd.dtsi
new file mode 100644
index 000000000000..25b480147541
--- /dev/null
+++ b/arch/arm64/boot/dts/tesla/fsd.dtsi
@@ -0,0 +1,652 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Tesla Full Self-Driving SoC device tree source
+ *
+ * Copyright (c) 2017-2022 Samsung Electronics Co., Ltd.
+ *		https://www.samsung.com
+ * Copyright (c) 2017-2022 Tesla, Inc.
+ *		https://www.tesla.com
+ */
+
+#include <dt-bindings/clock/fsd-clk.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+	compatible = "tesla,fsd";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	aliases {
+		i2c0 = &hsi2c_0;
+		i2c1 = &hsi2c_1;
+		i2c2 = &hsi2c_2;
+		i2c3 = &hsi2c_3;
+		i2c4 = &hsi2c_4;
+		i2c5 = &hsi2c_5;
+		i2c6 = &hsi2c_6;
+		i2c7 = &hsi2c_7;
+	};
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		cpu-map {
+			cluster0 {
+				core0 {
+					cpu = <&cpucl0_0>;
+				};
+				core1 {
+					cpu = <&cpucl0_1>;
+				};
+				core2 {
+					cpu = <&cpucl0_2>;
+				};
+				core3 {
+					cpu = <&cpucl0_3>;
+				};
+			};
+
+			cluster1 {
+				core0 {
+					cpu = <&cpucl1_0>;
+				};
+				core1 {
+					cpu = <&cpucl1_1>;
+				};
+				core2 {
+					cpu = <&cpucl1_2>;
+				};
+				core3 {
+					cpu = <&cpucl1_3>;
+				};
+			};
+
+			cluster2 {
+				core0 {
+					cpu = <&cpucl2_0>;
+				};
+				core1 {
+					cpu = <&cpucl2_1>;
+				};
+				core2 {
+					cpu = <&cpucl2_2>;
+				};
+				core3 {
+					cpu = <&cpucl2_3>;
+				};
+			};
+		};
+
+		/* Cluster 0 */
+		cpucl0_0: cpu@0 {
+				device_type = "cpu";
+				compatible = "arm,cortex-a72";
+				reg = <0x0 0x000>;
+				enable-method = "psci";
+				clock-frequency = <2400000000>;
+				cpu-idle-states = <&CPU_SLEEP>;
+		};
+
+		cpucl0_1: cpu@1 {
+				device_type = "cpu";
+				compatible = "arm,cortex-a72";
+				reg = <0x0 0x001>;
+				enable-method = "psci";
+				clock-frequency = <2400000000>;
+				cpu-idle-states = <&CPU_SLEEP>;
+		};
+
+		cpucl0_2: cpu@2 {
+				device_type = "cpu";
+				compatible = "arm,cortex-a72";
+				reg = <0x0 0x002>;
+				enable-method = "psci";
+				clock-frequency = <2400000000>;
+				cpu-idle-states = <&CPU_SLEEP>;
+		};
+
+		cpucl0_3: cpu@3 {
+				device_type = "cpu";
+				compatible = "arm,cortex-a72";
+				reg = <0x0 0x003>;
+				enable-method = "psci";
+				cpu-idle-states = <&CPU_SLEEP>;
+		};
+
+		/* Cluster 1 */
+		cpucl1_0: cpu@100 {
+				device_type = "cpu";
+				compatible = "arm,cortex-a72";
+				reg = <0x0 0x100>;
+				enable-method = "psci";
+				clock-frequency = <2400000000>;
+				cpu-idle-states = <&CPU_SLEEP>;
+		};
+
+		cpucl1_1: cpu@101 {
+				device_type = "cpu";
+				compatible = "arm,cortex-a72";
+				reg = <0x0 0x101>;
+				enable-method = "psci";
+				clock-frequency = <2400000000>;
+				cpu-idle-states = <&CPU_SLEEP>;
+		};
+
+		cpucl1_2: cpu@102 {
+				device_type = "cpu";
+				compatible = "arm,cortex-a72";
+				reg = <0x0 0x102>;
+				enable-method = "psci";
+				clock-frequency = <2400000000>;
+				cpu-idle-states = <&CPU_SLEEP>;
+		};
+
+		cpucl1_3: cpu@103 {
+				device_type = "cpu";
+				compatible = "arm,cortex-a72";
+				reg = <0x0 0x103>;
+				enable-method = "psci";
+				clock-frequency = <2400000000>;
+				cpu-idle-states = <&CPU_SLEEP>;
+		};
+
+		/* Cluster 2 */
+		cpucl2_0: cpu@200 {
+				device_type = "cpu";
+				compatible = "arm,cortex-a72";
+				reg = <0x0 0x200>;
+				enable-method = "psci";
+				clock-frequency = <2400000000>;
+				cpu-idle-states = <&CPU_SLEEP>;
+		};
+
+		cpucl2_1: cpu@201 {
+				device_type = "cpu";
+				compatible = "arm,cortex-a72";
+				reg = <0x0 0x201>;
+				enable-method = "psci";
+				clock-frequency = <2400000000>;
+				cpu-idle-states = <&CPU_SLEEP>;
+		};
+
+		cpucl2_2: cpu@202 {
+				device_type = "cpu";
+				compatible = "arm,cortex-a72";
+				reg = <0x0 0x202>;
+				enable-method = "psci";
+				clock-frequency = <2400000000>;
+				cpu-idle-states = <&CPU_SLEEP>;
+		};
+
+		cpucl2_3: cpu@203 {
+				device_type = "cpu";
+				compatible = "arm,cortex-a72";
+				reg = <0x0 0x203>;
+				enable-method = "psci";
+				clock-frequency = <2400000000>;
+				cpu-idle-states = <&CPU_SLEEP>;
+		};
+
+		idle-states {
+			entry-method = "psci";
+
+			CPU_SLEEP: cpu-sleep {
+				idle-state-name = "c2";
+				compatible = "arm,idle-state";
+				local-timer-stop;
+				arm,psci-suspend-param = <0x0010000>;
+				entry-latency-us = <30>;
+				exit-latency-us = <75>;
+				min-residency-us = <300>;
+			};
+		};
+	};
+
+	arm-pmu {
+		compatible = "arm,armv8-pmuv3";
+		interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 371 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 372 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 384 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 385 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 386 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 387 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-affinity = <&cpucl0_0>, <&cpucl0_1>, <&cpucl0_2>,
+				     <&cpucl0_3>, <&cpucl1_0>, <&cpucl1_1>,
+				     <&cpucl1_2>, <&cpucl1_3>, <&cpucl2_0>,
+				     <&cpucl2_1>, <&cpucl2_2>, <&cpucl2_3>;
+	};
+
+	psci {
+		compatible = "arm,psci-1.0";
+		method = "smc";
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+	};
+
+	fin_pll: clock {
+		compatible = "fixed-clock";
+		clock-output-names = "fin_pll";
+		#clock-cells = <0>;
+	};
+
+	soc: soc@0 {
+		compatible = "simple-bus";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges = <0x0 0x0 0x0 0x0 0x0 0x18000000>;
+		dma-ranges = <0x0 0x0 0x0 0x0 0x10 0x0>;
+
+		gic: interrupt-controller@10400000 {
+			compatible = "arm,gic-v3";
+			#interrupt-cells = <3>;
+			interrupt-controller;
+			reg =	<0x0 0x10400000 0x0 0x10000>, /* GICD */
+				<0x0 0x10600000 0x0 0x200000>; /* GICR_RD+GICR_SGI */
+			interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+		};
+
+		smmu_imem: iommu@10200000 {
+			compatible = "arm,mmu-500";
+			reg = <0x0 0x10200000 0x0 0x10000>;
+			#iommu-cells = <2>;
+			#global-interrupts = <7>;
+			interrupts = <GIC_SPI 438 IRQ_TYPE_LEVEL_HIGH>, /* Global secure fault */
+				     <GIC_SPI 439 IRQ_TYPE_LEVEL_HIGH>, /* Global non-secure fault */
+				     <GIC_SPI 451 IRQ_TYPE_LEVEL_HIGH>, /* Combined secure interrupt */
+				     <GIC_SPI 450 IRQ_TYPE_LEVEL_HIGH>, /* Combined non-secure interrupt */
+				     /* Performance counter interrupts */
+				     <GIC_SPI 441 IRQ_TYPE_LEVEL_HIGH>, /* for FSYS1_0 */
+				     <GIC_SPI 442 IRQ_TYPE_LEVEL_HIGH>, /* for FSYS1_1 */
+				     <GIC_SPI 443 IRQ_TYPE_LEVEL_HIGH>, /* for IMEM_0  */
+				     /* Per context non-secure context interrupts, 0-3 interrupts */
+				     <GIC_SPI 446 IRQ_TYPE_LEVEL_HIGH>, /* for CONTEXT_0 */
+				     <GIC_SPI 447 IRQ_TYPE_LEVEL_HIGH>, /* for CONTEXT_1 */
+				     <GIC_SPI 448 IRQ_TYPE_LEVEL_HIGH>, /* for CONTEXT_2 */
+				     <GIC_SPI 449 IRQ_TYPE_LEVEL_HIGH>; /* for CONTEXT_3 */
+		};
+
+		smmu_isp: iommu@12100000 {
+			compatible = "arm,mmu-500";
+			reg = <0x0 0x12100000 0x0 0x10000>;
+			#iommu-cells = <2>;
+			#global-interrupts = <11>;
+			interrupts = <GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH>, /* Global secure fault */
+				     <GIC_SPI 322 IRQ_TYPE_LEVEL_HIGH>, /* Global non-secure fault */
+				     <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>, /* Combined secure interrupt */
+				     <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>, /* Combined non-secure interrupt */
+				     /* Performance counter interrupts */
+				     <GIC_SPI 323 IRQ_TYPE_LEVEL_HIGH>, /* for CAM_CSI   */
+				     <GIC_SPI 324 IRQ_TYPE_LEVEL_HIGH>, /* for CAM_DP_0  */
+				     <GIC_SPI 325 IRQ_TYPE_LEVEL_HIGH>, /* for CAM_DP_1  */
+				     <GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH>, /* for CAM_ISP_0 */
+				     <GIC_SPI 327 IRQ_TYPE_LEVEL_HIGH>, /* for CAM_ISP_1 */
+				     <GIC_SPI 328 IRQ_TYPE_LEVEL_HIGH>, /* for CAM_MFC_0 */
+				     <GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>, /* for CAM_MFC_1 */
+				     /* Per context non-secure context interrupts, 0-7 interrupts */
+				     <GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>, /* for CONTEXT_0 */
+				     <GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH>, /* for CONTEXT_1 */
+				     <GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>, /* for CONTEXT_2 */
+				     <GIC_SPI 333 IRQ_TYPE_LEVEL_HIGH>, /* for CONTEXT_3 */
+				     <GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH>, /* for CONTEXT_4 */
+				     <GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH>, /* for CONTEXT_5 */
+				     <GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH>, /* for CONTEXT_6 */
+				     <GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH>; /* for CONTEXT_7 */
+		};
+
+		smmu_peric: iommu@14900000 {
+			compatible = "arm,mmu-500";
+			reg = <0x0 0x14900000 0x0 0x10000>;
+			#iommu-cells = <2>;
+			#global-interrupts = <5>;
+			interrupts = <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>, /* Global secure fault */
+				     <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>, /* Global non-secure fault */
+				     <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>, /* Combined secure interrupt */
+				     <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>, /* Combined non-secure interrupt */
+				     /* Performance counter interrupts */
+				     <GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>, /* for PERIC */
+				     /* Per context non-secure context interrupts, 0-1 interrupts */
+				     <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>, /* for CONTEXT_0 */
+				     <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>; /* for CONTEXT_1 */
+		};
+
+		smmu_fsys0: iommu@15450000 {
+			compatible = "arm,mmu-500";
+			reg = <0x0 0x15450000 0x0 0x10000>;
+			#iommu-cells = <2>;
+			#global-interrupts = <5>;
+			interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>, /* Global secure fault */
+				     <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>, /* Global non-secure fault */
+				     <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>, /* Combined secure interrupt */
+				     <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>, /* Combined non-secure interrupt */
+				     /* Performance counter interrupts */
+				     <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>, /* for FSYS0   */
+				     /* Per context non-secure context interrupts, 0-1 interrupts */
+				     <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>, /* for CONTEXT_0 */
+				     <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; /* for CONTEXT_1 */
+		};
+
+		clock_imem: clock-controller@10010000 {
+			compatible = "tesla,fsd-clock-imem";
+			reg = <0x0 0x10010000 0x0 0x3000>;
+			#clock-cells = <1>;
+			clocks = <&fin_pll>,
+				<&clock_cmu DOUT_CMU_IMEM_TCUCLK>,
+				<&clock_cmu DOUT_CMU_IMEM_ACLK>,
+				<&clock_cmu DOUT_CMU_IMEM_DMACLK>;
+			clock-names = "fin_pll",
+				"dout_cmu_imem_tcuclk",
+				"dout_cmu_imem_aclk",
+				"dout_cmu_imem_dmaclk";
+		};
+
+		clock_cmu: clock-controller@11c10000 {
+			compatible = "tesla,fsd-clock-cmu";
+			reg = <0x0 0x11c10000 0x0 0x3000>;
+			#clock-cells = <1>;
+			clocks = <&fin_pll>;
+			clock-names = "fin_pll";
+		};
+
+		clock_csi: clock-controller@12610000 {
+			compatible = "tesla,fsd-clock-cam_csi";
+			reg = <0x0 0x12610000 0x0 0x3000>;
+			#clock-cells = <1>;
+			clocks = <&fin_pll>;
+			clock-names = "fin_pll";
+		};
+
+		clock_mfc: clock-controller@12810000 {
+			compatible = "tesla,fsd-clock-mfc";
+			reg = <0x0 0x12810000 0x0 0x3000>;
+			#clock-cells = <1>;
+			clocks = <&fin_pll>;
+			clock-names = "fin_pll";
+		};
+
+		clock_peric: clock-controller@14010000 {
+			compatible = "tesla,fsd-clock-peric";
+			reg = <0x0 0x14010000 0x0 0x3000>;
+			#clock-cells = <1>;
+			clocks = <&fin_pll>,
+				<&clock_cmu DOUT_CMU_PLL_SHARED0_DIV4>,
+				<&clock_cmu DOUT_CMU_PERIC_SHARED1DIV36>,
+				<&clock_cmu DOUT_CMU_PERIC_SHARED0DIV3_TBUCLK>,
+				<&clock_cmu DOUT_CMU_PERIC_SHARED0DIV20>,
+				<&clock_cmu DOUT_CMU_PERIC_SHARED1DIV4_DMACLK>;
+			clock-names = "fin_pll",
+				"dout_cmu_pll_shared0_div4",
+				"dout_cmu_peric_shared1div36",
+				"dout_cmu_peric_shared0div3_tbuclk",
+				"dout_cmu_peric_shared0div20",
+				"dout_cmu_peric_shared1div4_dmaclk";
+		};
+
+		clock_fsys0: clock-controller@15010000 {
+			compatible = "tesla,fsd-clock-fsys0";
+			reg = <0x0 0x15010000 0x0 0x3000>;
+			#clock-cells = <1>;
+			clocks = <&fin_pll>,
+				<&clock_cmu DOUT_CMU_PLL_SHARED0_DIV6>,
+				<&clock_cmu DOUT_CMU_FSYS0_SHARED1DIV4>,
+				<&clock_cmu DOUT_CMU_FSYS0_SHARED0DIV4>;
+			clock-names = "fin_pll",
+				"dout_cmu_pll_shared0_div6",
+				"dout_cmu_fsys0_shared1div4",
+				"dout_cmu_fsys0_shared0div4";
+		};
+
+		clock_fsys1: clock-controller@16810000 {
+			compatible = "tesla,fsd-clock-fsys1";
+			reg = <0x0 0x16810000 0x0 0x3000>;
+			#clock-cells = <1>;
+			clocks = <&fin_pll>,
+				<&clock_cmu DOUT_CMU_FSYS1_SHARED0DIV8>,
+				<&clock_cmu DOUT_CMU_FSYS1_SHARED0DIV4>;
+			clock-names = "fin_pll",
+				"dout_cmu_fsys1_shared0div8",
+				"dout_cmu_fsys1_shared0div4";
+		};
+
+		mdma0: dma-controller@10100000 {
+			compatible = "arm,pl330", "arm,primecell";
+			reg = <0x0 0x10100000 0x0 0x1000>;
+			interrupts = <GIC_SPI 424 IRQ_TYPE_LEVEL_HIGH>;
+			#dma-cells = <1>;
+			#dma-channels = <8>;
+			#dma-requests = <32>;
+			clocks = <&clock_imem IMEM_DMA0_IPCLKPORT_ACLK>;
+			clock-names = "apb_pclk";
+			iommus = <&smmu_imem 0x800 0x0>;
+		};
+
+		mdma1: dma-controller@10110000 {
+			compatible = "arm,pl330", "arm,primecell";
+			reg = <0x0 0x10110000 0x0 0x1000>;
+			interrupts = <GIC_SPI 425 IRQ_TYPE_LEVEL_HIGH>;
+			#dma-cells = <1>;
+			#dma-channels = <8>;
+			#dma-requests = <32>;
+			clocks = <&clock_imem IMEM_DMA1_IPCLKPORT_ACLK>;
+			clock-names = "apb_pclk";
+			iommus = <&smmu_imem 0x801 0x0>;
+		};
+
+		pdma0: dma-controller@14280000 {
+			compatible = "arm,pl330", "arm,primecell";
+			reg = <0x0 0x14280000 0x0 0x1000>;
+			interrupts = <GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>;
+			#dma-cells = <1>;
+			#dma-channels = <8>;
+			#dma-requests = <32>;
+			clocks = <&clock_peric PERIC_DMA0_IPCLKPORT_ACLK>;
+			clock-names = "apb_pclk";
+			iommus = <&smmu_peric 0x2 0x0>;
+		};
+
+		pdma1: dma-controller@14290000 {
+			compatible = "arm,pl330", "arm,primecell";
+			reg = <0x0 0x14290000 0x0 0x1000>;
+			interrupts = <GIC_SPI 191 IRQ_TYPE_LEVEL_HIGH>;
+			#dma-cells = <1>;
+			#dma-channels = <8>;
+			#dma-requests = <32>;
+			clocks = <&clock_peric PERIC_DMA1_IPCLKPORT_ACLK>;
+			clock-names = "apb_pclk";
+			iommus = <&smmu_peric 0x1 0x0>;
+		};
+
+		serial_0: serial@14180000 {
+			compatible = "samsung,exynos4210-uart";
+			reg = <0x0 0x14180000 0x0 0x100>;
+			interrupts = <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&pdma1 1>, <&pdma1 0>;
+			dma-names = "rx", "tx";
+			clocks = <&clock_peric PERIC_PCLK_UART0>,
+				 <&clock_peric PERIC_SCLK_UART0>;
+			clock-names = "uart", "clk_uart_baud0";
+			status = "disabled";
+		};
+
+		serial_1: serial@14190000 {
+			compatible = "samsung,exynos4210-uart";
+			reg = <0x0 0x14190000 0x0 0x100>;
+			interrupts = <GIC_SPI 172 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&pdma1 3>, <&pdma1 2>;
+			dma-names = "rx", "tx";
+			clocks = <&clock_peric PERIC_PCLK_UART1>,
+				 <&clock_peric PERIC_SCLK_UART1>;
+			clock-names = "uart", "clk_uart_baud0";
+			status = "disabled";
+		};
+
+		pmu_system_controller: system-controller@11400000 {
+			compatible = "samsung,exynos7-pmu", "syscon";
+			reg = <0x0 0x11400000 0x0 0x5000>;
+		};
+
+		watchdog_0: watchdog@100a0000 {
+			compatible = "samsung,exynos7-wdt";
+			reg = <0x0 0x100a0000 0x0 0x100>;
+			interrupts = <GIC_SPI 471 IRQ_TYPE_LEVEL_HIGH>;
+			samsung,syscon-phandle = <&pmu_system_controller>;
+			clocks = <&fin_pll>;
+			clock-names = "watchdog";
+		};
+
+		watchdog_1: watchdog@100b0000 {
+			compatible = "samsung,exynos7-wdt";
+			reg = <0x0 0x100b0000 0x0 0x100>;
+			interrupts = <GIC_SPI 472 IRQ_TYPE_LEVEL_HIGH>;
+			samsung,syscon-phandle = <&pmu_system_controller>;
+			clocks = <&fin_pll>;
+			clock-names = "watchdog";
+		};
+
+		watchdog_2: watchdog@100c0000 {
+			compatible = "samsung,exynos7-wdt";
+			reg = <0x0 0x100c0000 0x0 0x100>;
+			interrupts = <GIC_SPI 473 IRQ_TYPE_LEVEL_HIGH>;
+			samsung,syscon-phandle = <&pmu_system_controller>;
+			clocks = <&fin_pll>;
+			clock-names = "watchdog";
+		};
+
+		pwm_0: pwm@14100000 {
+			compatible = "samsung,exynos4210-pwm";
+			reg = <0x0 0x14100000 0x0 0x100>;
+			samsung,pwm-outputs = <0>, <1>, <2>, <3>;
+			#pwm-cells = <3>;
+			clocks = <&clock_peric PERIC_PWM0_IPCLKPORT_I_PCLK_S0>;
+			clock-names = "timers";
+			status = "disabled";
+		};
+
+		pwm_1: pwm@14110000 {
+			compatible = "samsung,exynos4210-pwm";
+			reg = <0x0 0x14110000 0x0 0x100>;
+			samsung,pwm-outputs = <0>, <1>, <2>, <3>;
+			#pwm-cells = <3>;
+			clocks = <&clock_peric PERIC_PWM1_IPCLKPORT_I_PCLK_S0>;
+			clock-names = "timers";
+			status = "disabled";
+		};
+
+		hsi2c_0: i2c@14200000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x0 0x14200000 0x0 0x1000>;
+			interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c0_bus>;
+			clocks = <&clock_peric PERIC_PCLK_HSI2C0>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_1: i2c@14210000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x0 0x14210000 0x0 0x1000>;
+			interrupts = <GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c1_bus>;
+			clocks = <&clock_peric PERIC_PCLK_HSI2C1>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_2: i2c@14220000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x0 0x14220000 0x0 0x1000>;
+			interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c2_bus>;
+			clocks = <&clock_peric PERIC_PCLK_HSI2C2>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_3: i2c@14230000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x0 0x14230000 0x0 0x1000>;
+			interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c3_bus>;
+			clocks = <&clock_peric PERIC_PCLK_HSI2C3>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_4: i2c@14240000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x0 0x14240000 0x0 0x1000>;
+			interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c4_bus>;
+			clocks = <&clock_peric PERIC_PCLK_HSI2C4>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_5: i2c@14250000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x0 0x14250000 0x0 0x1000>;
+			interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c5_bus>;
+			clocks = <&clock_peric PERIC_PCLK_HSI2C5>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_6: i2c@14260000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x0 0x14260000 0x0 0x1000>;
+			interrupts = <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c6_bus>;
+			clocks = <&clock_peric PERIC_PCLK_HSI2C6>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+
+		hsi2c_7: i2c@14270000 {
+			compatible = "samsung,exynos7-hsi2c";
+			reg = <0x0 0x14270000 0x0 0x1000>;
+			interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&hs_i2c7_bus>;
+			clocks = <&clock_peric PERIC_PCLK_HSI2C7>;
+			clock-names = "hsi2c";
+			status = "disabled";
+		};
+	};
+};
-- 
2.25.1


^ permalink raw reply related

* [PATCH v5 13/16] dt-bindings: arm: add Tesla FSD ARM SoC
From: Alim Akhtar @ 2022-01-24 14:16 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel
  Cc: soc, linux-clk, devicetree, olof, arnd, linus.walleij,
	catalin.marinas, robh+dt, krzysztof.kozlowski, s.nawrocki,
	linux-samsung-soc, pankaj.dubey, sboyd, Alim Akhtar, linux-fsd
In-Reply-To: <20220124141644.71052-1-alim.akhtar@samsung.com>

Add device tree bindings for the Tesla FSD ARM SoC.

Cc: linux-fsd@tesla.com
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
---
 .../devicetree/bindings/arm/tesla.yaml        | 27 +++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/tesla.yaml

diff --git a/Documentation/devicetree/bindings/arm/tesla.yaml b/Documentation/devicetree/bindings/arm/tesla.yaml
new file mode 100644
index 000000000000..09856da657dc
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/tesla.yaml
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/tesla.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tesla Full Self Driving(FSD) platforms device tree bindings
+
+maintainers:
+  - Alim Akhtar <alim.akhtar@samsung.com>
+  - linux-fsd@tesla.com
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+
+      - description: FSD SoC board
+        items:
+          - enum:
+              - tesla,fsd-evb   # Tesla FSD Evaluation
+          - const: tesla,fsd
+
+additionalProperties: true
+
+...
-- 
2.25.1


^ permalink raw reply related

* [PATCH v5 12/16] pinctrl: samsung: add FSD SoC specific data
From: Alim Akhtar @ 2022-01-24 14:16 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel
  Cc: soc, linux-clk, devicetree, olof, arnd, linus.walleij,
	catalin.marinas, robh+dt, krzysztof.kozlowski, s.nawrocki,
	linux-samsung-soc, pankaj.dubey, sboyd, Alim Akhtar, linux-fsd,
	Ajay Kumar
In-Reply-To: <20220124141644.71052-1-alim.akhtar@samsung.com>

Adds Tesla FSD SoC specific data to enable pinctrl.
FSD SoC has similar pinctrl controller as found in the most
Samsung/Exynos SoCs.

Cc: linux-fsd@tesla.com
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
---
 .../pinctrl/samsung/pinctrl-exynos-arm64.c    | 71 +++++++++++++++++++
 drivers/pinctrl/samsung/pinctrl-samsung.c     |  2 +
 drivers/pinctrl/samsung/pinctrl-samsung.h     |  1 +
 3 files changed, 74 insertions(+)

diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
index 4102ce955bd7..d291819c2f77 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
@@ -725,3 +725,74 @@ const struct samsung_pinctrl_of_match_data exynosautov9_of_data __initconst = {
 	.ctrl		= exynosautov9_pin_ctrl,
 	.num_ctrl	= ARRAY_SIZE(exynosautov9_pin_ctrl),
 };
+
+/*
+ * Pinctrl driver data for Tesla FSD SoC. FSD SoC includes three
+ * gpio/pin-mux/pinconfig controllers.
+ */
+
+/* pin banks of FSD pin-controller 0 (FSYS) */
+static const struct samsung_pin_bank_data fsd_pin_banks0[] __initconst = {
+	EXYNOS850_PIN_BANK_EINTG(7, 0x00, "gpf0", 0x00),
+	EXYNOS850_PIN_BANK_EINTG(8, 0x20, "gpf1", 0x04),
+	EXYNOS850_PIN_BANK_EINTG(3, 0x40, "gpf6", 0x08),
+	EXYNOS850_PIN_BANK_EINTG(2, 0x60, "gpf4", 0x0c),
+	EXYNOS850_PIN_BANK_EINTG(6, 0x80, "gpf5", 0x10),
+};
+
+/* pin banks of FSD pin-controller 1 (PERIC) */
+static const struct samsung_pin_bank_data fsd_pin_banks1[] __initconst = {
+	EXYNOS850_PIN_BANK_EINTG(4, 0x000, "gpc8", 0x00),
+	EXYNOS850_PIN_BANK_EINTG(7, 0x020, "gpf2", 0x04),
+	EXYNOS850_PIN_BANK_EINTG(8, 0x040, "gpf3", 0x08),
+	EXYNOS850_PIN_BANK_EINTG(8, 0x060, "gpd0", 0x0c),
+	EXYNOS850_PIN_BANK_EINTG(8, 0x080, "gpb0", 0x10),
+	EXYNOS850_PIN_BANK_EINTG(8, 0x0a0, "gpb1", 0x14),
+	EXYNOS850_PIN_BANK_EINTG(8, 0x0c0, "gpb4", 0x18),
+	EXYNOS850_PIN_BANK_EINTG(4, 0x0e0, "gpb5", 0x1c),
+	EXYNOS850_PIN_BANK_EINTG(8, 0x100, "gpb6", 0x20),
+	EXYNOS850_PIN_BANK_EINTG(8, 0x120, "gpb7", 0x24),
+	EXYNOS850_PIN_BANK_EINTG(5, 0x140, "gpd1", 0x28),
+	EXYNOS850_PIN_BANK_EINTG(5, 0x160, "gpd2", 0x2c),
+	EXYNOS850_PIN_BANK_EINTG(7, 0x180, "gpd3", 0x30),
+	EXYNOS850_PIN_BANK_EINTG(8, 0x1a0, "gpg0", 0x34),
+	EXYNOS850_PIN_BANK_EINTG(8, 0x1c0, "gpg1", 0x38),
+	EXYNOS850_PIN_BANK_EINTG(8, 0x1e0, "gpg2", 0x3c),
+	EXYNOS850_PIN_BANK_EINTG(8, 0x200, "gpg3", 0x40),
+	EXYNOS850_PIN_BANK_EINTG(8, 0x220, "gpg4", 0x44),
+	EXYNOS850_PIN_BANK_EINTG(8, 0x240, "gpg5", 0x48),
+	EXYNOS850_PIN_BANK_EINTG(8, 0x260, "gpg6", 0x4c),
+	EXYNOS850_PIN_BANK_EINTG(8, 0x280, "gpg7", 0x50),
+};
+
+/* pin banks of FSD pin-controller 2 (PMU) */
+static const struct samsung_pin_bank_data fsd_pin_banks2[] __initconst = {
+	EXYNOS850_PIN_BANK_EINTN(3, 0x00, "gpq0"),
+};
+
+const struct samsung_pin_ctrl fsd_pin_ctrl[] __initconst = {
+	{
+		/* pin-controller instance 0 FSYS0 data */
+		.pin_banks	= fsd_pin_banks0,
+		.nr_banks	= ARRAY_SIZE(fsd_pin_banks0),
+		.eint_gpio_init = exynos_eint_gpio_init,
+		.suspend	= exynos_pinctrl_suspend,
+		.resume		= exynos_pinctrl_resume,
+	}, {
+		/* pin-controller instance 1 PERIC data */
+		.pin_banks	= fsd_pin_banks1,
+		.nr_banks	= ARRAY_SIZE(fsd_pin_banks1),
+		.eint_gpio_init = exynos_eint_gpio_init,
+		.suspend	= exynos_pinctrl_suspend,
+		.resume		= exynos_pinctrl_resume,
+	}, {
+		/* pin-controller instance 2 PMU data */
+		.pin_banks	= fsd_pin_banks2,
+		.nr_banks	= ARRAY_SIZE(fsd_pin_banks2),
+	},
+};
+
+const struct samsung_pinctrl_of_match_data fsd_of_data __initconst = {
+	.ctrl		= fsd_pin_ctrl,
+	.num_ctrl	= ARRAY_SIZE(fsd_pin_ctrl),
+};
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c
index 568b6e65dfed..f610beab23a0 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.c
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.c
@@ -1320,6 +1320,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = {
 		.data = &exynos850_of_data },
 	{ .compatible = "samsung,exynosautov9-pinctrl",
 		.data = &exynosautov9_of_data },
+	{ .compatible = "tesla,fsd-pinctrl",
+		.data = &fsd_of_data },
 #endif
 #ifdef CONFIG_PINCTRL_S3C64XX
 	{ .compatible = "samsung,s3c64xx-pinctrl",
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h
index 1f8d30ba05af..5b32d3f30fcd 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.h
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.h
@@ -342,6 +342,7 @@ extern const struct samsung_pinctrl_of_match_data exynos7_of_data;
 extern const struct samsung_pinctrl_of_match_data exynos7885_of_data;
 extern const struct samsung_pinctrl_of_match_data exynos850_of_data;
 extern const struct samsung_pinctrl_of_match_data exynosautov9_of_data;
+extern const struct samsung_pinctrl_of_match_data fsd_of_data;
 extern const struct samsung_pinctrl_of_match_data s3c64xx_of_data;
 extern const struct samsung_pinctrl_of_match_data s3c2412_of_data;
 extern const struct samsung_pinctrl_of_match_data s3c2416_of_data;
-- 
2.25.1


^ permalink raw reply related

* [PATCH v5 09/16] clk: samsung: fsd: Add cmu_mfc block clock information
From: Alim Akhtar @ 2022-01-24 14:16 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel
  Cc: soc, linux-clk, devicetree, olof, arnd, linus.walleij,
	catalin.marinas, robh+dt, krzysztof.kozlowski, s.nawrocki,
	linux-samsung-soc, pankaj.dubey, sboyd, Alim Akhtar, linux-fsd,
	Smitha T Murthy
In-Reply-To: <20220124141644.71052-1-alim.akhtar@samsung.com>

Adds cmu_mfc clock related code, these clocks are
required for MFC IP.

Cc: linux-fsd@tesla.com
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
Signed-off-by: Smitha T Murthy <smitha.t@samsung.com>
Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
---
 drivers/clk/samsung/clk-fsd.c | 121 ++++++++++++++++++++++++++++++++++
 1 file changed, 121 insertions(+)

diff --git a/drivers/clk/samsung/clk-fsd.c b/drivers/clk/samsung/clk-fsd.c
index f15b5b6b8eca..f9c4b4c5e0cb 100644
--- a/drivers/clk/samsung/clk-fsd.c
+++ b/drivers/clk/samsung/clk-fsd.c
@@ -1427,6 +1427,124 @@ static void __init fsd_clk_imem_init(struct device_node *np)
 
 CLK_OF_DECLARE(fsd_clk_imem, "tesla,fsd-clock-imem", fsd_clk_imem_init);
 
+/* Register Offset definitions for CMU_MFC (0x12810000) */
+#define PLL_LOCKTIME_PLL_MFC					0x0
+#define PLL_CON0_PLL_MFC					0x100
+#define MUX_MFC_BUSD						0x1000
+#define MUX_MFC_BUSP						0x1008
+#define DIV_MFC_BUSD_DIV4					0x1800
+#define GAT_MFC_CMU_MFC_IPCLKPORT_PCLK				0x2000
+#define GAT_MFC_AS_P_MFC_IPCLKPORT_PCLKM			0x2004
+#define GAT_MFC_AS_P_MFC_IPCLKPORT_PCLKS			0x2008
+#define GAT_MFC_AXI2APB_MFC_IPCLKPORT_ACLK			0x200c
+#define GAT_MFC_MFC_IPCLKPORT_ACLK				0x2010
+#define GAT_MFC_NS_BRDG_MFC_IPCLKPORT_CLK__PMFC__CLK_MFC_D	0x2018
+#define GAT_MFC_NS_BRDG_MFC_IPCLKPORT_CLK__PMFC__CLK_MFC_P	0x201c
+#define GAT_MFC_PPMU_MFCD0_IPCLKPORT_ACLK			0x2028
+#define GAT_MFC_PPMU_MFCD0_IPCLKPORT_PCLK			0x202c
+#define GAT_MFC_PPMU_MFCD1_IPCLKPORT_ACLK			0x2030
+#define GAT_MFC_PPMU_MFCD1_IPCLKPORT_PCLK			0x2034
+#define GAT_MFC_SYSREG_MFC_IPCLKPORT_PCLK			0x2038
+#define GAT_MFC_TBU_MFCD0_IPCLKPORT_CLK				0x203c
+#define GAT_MFC_TBU_MFCD1_IPCLKPORT_CLK				0x2040
+#define GAT_MFC_BUSD_DIV4_GATE					0x2044
+#define GAT_MFC_BUSD_GATE					0x2048
+
+static const unsigned long mfc_clk_regs[] __initconst = {
+	PLL_LOCKTIME_PLL_MFC,
+	PLL_CON0_PLL_MFC,
+	MUX_MFC_BUSD,
+	MUX_MFC_BUSP,
+	DIV_MFC_BUSD_DIV4,
+	GAT_MFC_CMU_MFC_IPCLKPORT_PCLK,
+	GAT_MFC_AS_P_MFC_IPCLKPORT_PCLKM,
+	GAT_MFC_AS_P_MFC_IPCLKPORT_PCLKS,
+	GAT_MFC_AXI2APB_MFC_IPCLKPORT_ACLK,
+	GAT_MFC_MFC_IPCLKPORT_ACLK,
+	GAT_MFC_NS_BRDG_MFC_IPCLKPORT_CLK__PMFC__CLK_MFC_D,
+	GAT_MFC_NS_BRDG_MFC_IPCLKPORT_CLK__PMFC__CLK_MFC_P,
+	GAT_MFC_PPMU_MFCD0_IPCLKPORT_ACLK,
+	GAT_MFC_PPMU_MFCD0_IPCLKPORT_PCLK,
+	GAT_MFC_PPMU_MFCD1_IPCLKPORT_ACLK,
+	GAT_MFC_PPMU_MFCD1_IPCLKPORT_PCLK,
+	GAT_MFC_SYSREG_MFC_IPCLKPORT_PCLK,
+	GAT_MFC_TBU_MFCD0_IPCLKPORT_CLK,
+	GAT_MFC_TBU_MFCD1_IPCLKPORT_CLK,
+	GAT_MFC_BUSD_DIV4_GATE,
+	GAT_MFC_BUSD_GATE,
+};
+
+static const struct samsung_pll_rate_table pll_mfc_rate_table[] __initconst = {
+	PLL_35XX_RATE(24 * MHZ, 666000000U, 111, 4, 0),
+};
+
+static const struct samsung_pll_clock mfc_pll_clks[] __initconst = {
+	PLL(pll_142xx, 0, "fout_pll_mfc", "fin_pll",
+	    PLL_LOCKTIME_PLL_MFC, PLL_CON0_PLL_MFC, pll_mfc_rate_table),
+};
+
+PNAME(mout_mfc_pll_p) = { "fin_pll", "fout_pll_mfc" };
+PNAME(mout_mfc_busp_p) = { "fin_pll", "dout_mfc_busd_div4" };
+PNAME(mout_mfc_busd_p) = { "fin_pll", "mfc_busd_gate" };
+
+static const struct samsung_mux_clock mfc_mux_clks[] __initconst = {
+	MUX(0, "mout_mfc_pll", mout_mfc_pll_p, PLL_CON0_PLL_MFC, 4, 1),
+	MUX(0, "mout_mfc_busp", mout_mfc_busp_p, MUX_MFC_BUSP, 0, 1),
+	MUX(0, "mout_mfc_busd", mout_mfc_busd_p, MUX_MFC_BUSD, 0, 1),
+};
+
+static const struct samsung_div_clock mfc_div_clks[] __initconst = {
+	DIV(0, "dout_mfc_busd_div4", "mfc_busd_div4_gate", DIV_MFC_BUSD_DIV4, 0, 4),
+};
+
+static const struct samsung_gate_clock mfc_gate_clks[] __initconst = {
+	GATE(0, "mfc_cmu_mfc_ipclkport_pclk", "mout_mfc_busp",
+	     GAT_MFC_CMU_MFC_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "mfc_as_p_mfc_ipclkport_pclkm", "mout_mfc_busd",
+	     GAT_MFC_AS_P_MFC_IPCLKPORT_PCLKM, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "mfc_as_p_mfc_ipclkport_pclks", "mout_mfc_busp",
+	     GAT_MFC_AS_P_MFC_IPCLKPORT_PCLKS, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "mfc_axi2apb_mfc_ipclkport_aclk", "mout_mfc_busp",
+	     GAT_MFC_AXI2APB_MFC_IPCLKPORT_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(MFC_MFC_IPCLKPORT_ACLK, "mfc_mfc_ipclkport_aclk", "mout_mfc_busd",
+	     GAT_MFC_MFC_IPCLKPORT_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "mfc_ns_brdg_mfc_ipclkport_clk__pmfc__clk_mfc_d", "mout_mfc_busd",
+	     GAT_MFC_NS_BRDG_MFC_IPCLKPORT_CLK__PMFC__CLK_MFC_D, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "mfc_ns_brdg_mfc_ipclkport_clk__pmfc__clk_mfc_p", "mout_mfc_busp",
+	     GAT_MFC_NS_BRDG_MFC_IPCLKPORT_CLK__PMFC__CLK_MFC_P, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "mfc_ppmu_mfcd0_ipclkport_aclk", "mout_mfc_busd",
+	     GAT_MFC_PPMU_MFCD0_IPCLKPORT_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "mfc_ppmu_mfcd0_ipclkport_pclk", "mout_mfc_busp",
+	     GAT_MFC_PPMU_MFCD0_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "mfc_ppmu_mfcd1_ipclkport_aclk", "mout_mfc_busd",
+	     GAT_MFC_PPMU_MFCD1_IPCLKPORT_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "mfc_ppmu_mfcd1_ipclkport_pclk", "mout_mfc_busp",
+	     GAT_MFC_PPMU_MFCD1_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "mfc_sysreg_mfc_ipclkport_pclk", "mout_mfc_busp",
+	     GAT_MFC_SYSREG_MFC_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "mfc_tbu_mfcd0_ipclkport_clk", "mout_mfc_busd",
+	     GAT_MFC_TBU_MFCD0_IPCLKPORT_CLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "mfc_tbu_mfcd1_ipclkport_clk", "mout_mfc_busd",
+	     GAT_MFC_TBU_MFCD1_IPCLKPORT_CLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "mfc_busd_div4_gate", "mout_mfc_pll",
+	     GAT_MFC_BUSD_DIV4_GATE, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "mfc_busd_gate", "mout_mfc_pll", GAT_MFC_BUSD_GATE, 21, CLK_IS_CRITICAL, 0),
+};
+
+static const struct samsung_cmu_info mfc_cmu_info __initconst = {
+	.pll_clks		= mfc_pll_clks,
+	.nr_pll_clks		= ARRAY_SIZE(mfc_pll_clks),
+	.mux_clks		= mfc_mux_clks,
+	.nr_mux_clks		= ARRAY_SIZE(mfc_mux_clks),
+	.div_clks		= mfc_div_clks,
+	.nr_div_clks		= ARRAY_SIZE(mfc_div_clks),
+	.gate_clks		= mfc_gate_clks,
+	.nr_gate_clks		= ARRAY_SIZE(mfc_gate_clks),
+	.nr_clk_ids		= MFC_NR_CLK,
+	.clk_regs		= mfc_clk_regs,
+	.nr_clk_regs		= ARRAY_SIZE(mfc_clk_regs),
+};
+
 /**
  * fsd_cmu_probe - Probe function for FSD platform clocks
  * @pdev: Pointer to platform device
@@ -1455,6 +1573,9 @@ static const struct of_device_id fsd_cmu_of_match[] = {
 	}, {
 		.compatible = "tesla,fsd-clock-fsys1",
 		.data = &fsys1_cmu_info,
+	}, {
+		.compatible = "tesla,fsd-clock-mfc",
+		.data = &mfc_cmu_info,
 	}, {
 	},
 };
-- 
2.25.1


^ permalink raw reply related

* [PATCH v5 10/16] clk: samsung: fsd: Add cam_csi block clock information
From: Alim Akhtar @ 2022-01-24 14:16 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel
  Cc: soc, linux-clk, devicetree, olof, arnd, linus.walleij,
	catalin.marinas, robh+dt, krzysztof.kozlowski, s.nawrocki,
	linux-samsung-soc, pankaj.dubey, sboyd, Alim Akhtar, linux-fsd,
	Sathyakam M
In-Reply-To: <20220124141644.71052-1-alim.akhtar@samsung.com>

Adds clocks for BLK_CAM_CSI block, this is needed for CSI to work.

Cc: linux-fsd@tesla.com
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
Signed-off-by: Sathyakam M <sathya@samsung.com>
Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
---
 drivers/clk/samsung/clk-fsd.c | 207 ++++++++++++++++++++++++++++++++++
 1 file changed, 207 insertions(+)

diff --git a/drivers/clk/samsung/clk-fsd.c b/drivers/clk/samsung/clk-fsd.c
index f9c4b4c5e0cb..5d009c70e97d 100644
--- a/drivers/clk/samsung/clk-fsd.c
+++ b/drivers/clk/samsung/clk-fsd.c
@@ -1545,6 +1545,210 @@ static const struct samsung_cmu_info mfc_cmu_info __initconst = {
 	.nr_clk_regs		= ARRAY_SIZE(mfc_clk_regs),
 };
 
+/* Register Offset definitions for CMU_CAM_CSI (0x12610000) */
+#define PLL_LOCKTIME_PLL_CAM_CSI		0x0
+#define PLL_CON0_PLL_CAM_CSI			0x100
+#define DIV_CAM_CSI0_ACLK			0x1800
+#define DIV_CAM_CSI1_ACLK			0x1804
+#define DIV_CAM_CSI2_ACLK			0x1808
+#define DIV_CAM_CSI_BUSD			0x180c
+#define DIV_CAM_CSI_BUSP			0x1810
+#define GAT_CAM_CSI_CMU_CAM_CSI_IPCLKPORT_PCLK	0x2000
+#define GAT_CAM_AXI2APB_CAM_CSI_IPCLKPORT_ACLK	0x2004
+#define GAT_CAM_CSI_BUS_D_CAM_CSI_IPCLKPORT_CLK__SYSTEM__CLK_CSI0	0x2008
+#define GAT_CAM_CSI_BUS_D_CAM_CSI_IPCLKPORT_CLK__SYSTEM__CLK_CSI1	0x200c
+#define GAT_CAM_CSI_BUS_D_CAM_CSI_IPCLKPORT_CLK__SYSTEM__CLK_CSI2	0x2010
+#define GAT_CAM_CSI_BUS_D_CAM_CSI_IPCLKPORT_CLK__SYSTEM__CLK_SOC_NOC	0x2014
+#define GAT_CAM_CSI_BUS_D_CAM_CSI_IPCLKPORT_CLK__SYSTEM__NOC		0x2018
+#define GAT_CAM_CSI0_0_IPCLKPORT_I_ACLK		0x201c
+#define GAT_CAM_CSI0_0_IPCLKPORT_I_PCLK		0x2020
+#define GAT_CAM_CSI0_1_IPCLKPORT_I_ACLK		0x2024
+#define GAT_CAM_CSI0_1_IPCLKPORT_I_PCLK		0x2028
+#define GAT_CAM_CSI0_2_IPCLKPORT_I_ACLK		0x202c
+#define GAT_CAM_CSI0_2_IPCLKPORT_I_PCLK		0x2030
+#define GAT_CAM_CSI0_3_IPCLKPORT_I_ACLK		0x2034
+#define GAT_CAM_CSI0_3_IPCLKPORT_I_PCLK		0x2038
+#define GAT_CAM_CSI1_0_IPCLKPORT_I_ACLK		0x203c
+#define GAT_CAM_CSI1_0_IPCLKPORT_I_PCLK		0x2040
+#define GAT_CAM_CSI1_1_IPCLKPORT_I_ACLK		0x2044
+#define GAT_CAM_CSI1_1_IPCLKPORT_I_PCLK		0x2048
+#define GAT_CAM_CSI1_2_IPCLKPORT_I_ACLK		0x204c
+#define GAT_CAM_CSI1_2_IPCLKPORT_I_PCLK		0x2050
+#define GAT_CAM_CSI1_3_IPCLKPORT_I_ACLK		0x2054
+#define GAT_CAM_CSI1_3_IPCLKPORT_I_PCLK		0x2058
+#define GAT_CAM_CSI2_0_IPCLKPORT_I_ACLK		0x205c
+#define GAT_CAM_CSI2_0_IPCLKPORT_I_PCLK		0x2060
+#define GAT_CAM_CSI2_1_IPCLKPORT_I_ACLK		0x2064
+#define GAT_CAM_CSI2_1_IPCLKPORT_I_PCLK		0x2068
+#define GAT_CAM_CSI2_2_IPCLKPORT_I_ACLK		0x206c
+#define GAT_CAM_CSI2_2_IPCLKPORT_I_PCLK		0x2070
+#define GAT_CAM_CSI2_3_IPCLKPORT_I_ACLK		0x2074
+#define GAT_CAM_CSI2_3_IPCLKPORT_I_PCLK		0x2078
+#define GAT_CAM_NS_BRDG_CAM_CSI_IPCLKPORT_CLK__PSOC_CAM_CSI__CLK_CAM_CSI_D	0x207c
+#define GAT_CAM_NS_BRDG_CAM_CSI_IPCLKPORT_CLK__PSOC_CAM_CSI__CLK_CAM_CSI_P	0x2080
+#define GAT_CAM_SYSREG_CAM_CSI_IPCLKPORT_PCLK	0x2084
+#define GAT_CAM_TBU_CAM_CSI_IPCLKPORT_ACLK	0x2088
+
+static const unsigned long cam_csi_clk_regs[] __initconst = {
+	PLL_LOCKTIME_PLL_CAM_CSI,
+	PLL_CON0_PLL_CAM_CSI,
+	DIV_CAM_CSI0_ACLK,
+	DIV_CAM_CSI1_ACLK,
+	DIV_CAM_CSI2_ACLK,
+	DIV_CAM_CSI_BUSD,
+	DIV_CAM_CSI_BUSP,
+	GAT_CAM_CSI_CMU_CAM_CSI_IPCLKPORT_PCLK,
+	GAT_CAM_AXI2APB_CAM_CSI_IPCLKPORT_ACLK,
+	GAT_CAM_CSI_BUS_D_CAM_CSI_IPCLKPORT_CLK__SYSTEM__CLK_CSI0,
+	GAT_CAM_CSI_BUS_D_CAM_CSI_IPCLKPORT_CLK__SYSTEM__CLK_CSI1,
+	GAT_CAM_CSI_BUS_D_CAM_CSI_IPCLKPORT_CLK__SYSTEM__CLK_CSI2,
+	GAT_CAM_CSI_BUS_D_CAM_CSI_IPCLKPORT_CLK__SYSTEM__CLK_SOC_NOC,
+	GAT_CAM_CSI_BUS_D_CAM_CSI_IPCLKPORT_CLK__SYSTEM__NOC,
+	GAT_CAM_CSI0_0_IPCLKPORT_I_ACLK,
+	GAT_CAM_CSI0_0_IPCLKPORT_I_PCLK,
+	GAT_CAM_CSI0_1_IPCLKPORT_I_ACLK,
+	GAT_CAM_CSI0_1_IPCLKPORT_I_PCLK,
+	GAT_CAM_CSI0_2_IPCLKPORT_I_ACLK,
+	GAT_CAM_CSI0_2_IPCLKPORT_I_PCLK,
+	GAT_CAM_CSI0_3_IPCLKPORT_I_ACLK,
+	GAT_CAM_CSI0_3_IPCLKPORT_I_PCLK,
+	GAT_CAM_CSI1_0_IPCLKPORT_I_ACLK,
+	GAT_CAM_CSI1_0_IPCLKPORT_I_PCLK,
+	GAT_CAM_CSI1_1_IPCLKPORT_I_ACLK,
+	GAT_CAM_CSI1_1_IPCLKPORT_I_PCLK,
+	GAT_CAM_CSI1_2_IPCLKPORT_I_ACLK,
+	GAT_CAM_CSI1_2_IPCLKPORT_I_PCLK,
+	GAT_CAM_CSI1_3_IPCLKPORT_I_ACLK,
+	GAT_CAM_CSI1_3_IPCLKPORT_I_PCLK,
+	GAT_CAM_CSI2_0_IPCLKPORT_I_ACLK,
+	GAT_CAM_CSI2_0_IPCLKPORT_I_PCLK,
+	GAT_CAM_CSI2_1_IPCLKPORT_I_ACLK,
+	GAT_CAM_CSI2_1_IPCLKPORT_I_PCLK,
+	GAT_CAM_CSI2_2_IPCLKPORT_I_ACLK,
+	GAT_CAM_CSI2_2_IPCLKPORT_I_PCLK,
+	GAT_CAM_CSI2_3_IPCLKPORT_I_ACLK,
+	GAT_CAM_CSI2_3_IPCLKPORT_I_PCLK,
+	GAT_CAM_NS_BRDG_CAM_CSI_IPCLKPORT_CLK__PSOC_CAM_CSI__CLK_CAM_CSI_D,
+	GAT_CAM_NS_BRDG_CAM_CSI_IPCLKPORT_CLK__PSOC_CAM_CSI__CLK_CAM_CSI_P,
+	GAT_CAM_SYSREG_CAM_CSI_IPCLKPORT_PCLK,
+	GAT_CAM_TBU_CAM_CSI_IPCLKPORT_ACLK,
+};
+
+static const struct samsung_pll_rate_table pll_cam_csi_rate_table[] __initconst = {
+	PLL_35XX_RATE(24 * MHZ, 1066000000U, 533, 12, 0),
+};
+
+static const struct samsung_pll_clock cam_csi_pll_clks[] __initconst = {
+	PLL(pll_142xx, 0, "fout_pll_cam_csi", "fin_pll",
+	    PLL_LOCKTIME_PLL_CAM_CSI, PLL_CON0_PLL_CAM_CSI, pll_cam_csi_rate_table),
+};
+
+PNAME(mout_cam_csi_pll_p) = { "fin_pll", "fout_pll_cam_csi" };
+
+static const struct samsung_mux_clock cam_csi_mux_clks[] __initconst = {
+	MUX(0, "mout_cam_csi_pll", mout_cam_csi_pll_p, PLL_CON0_PLL_CAM_CSI, 4, 1),
+};
+
+static const struct samsung_div_clock cam_csi_div_clks[] __initconst = {
+	DIV(0, "dout_cam_csi0_aclk", "mout_cam_csi_pll", DIV_CAM_CSI0_ACLK, 0, 4),
+	DIV(0, "dout_cam_csi1_aclk", "mout_cam_csi_pll", DIV_CAM_CSI1_ACLK, 0, 4),
+	DIV(0, "dout_cam_csi2_aclk", "mout_cam_csi_pll", DIV_CAM_CSI2_ACLK, 0, 4),
+	DIV(0, "dout_cam_csi_busd", "mout_cam_csi_pll", DIV_CAM_CSI_BUSD, 0, 4),
+	DIV(0, "dout_cam_csi_busp", "mout_cam_csi_pll", DIV_CAM_CSI_BUSP, 0, 4),
+};
+
+static const struct samsung_gate_clock cam_csi_gate_clks[] __initconst = {
+	GATE(0, "cam_csi_cmu_cam_csi_ipclkport_pclk", "dout_cam_csi_busp",
+	     GAT_CAM_CSI_CMU_CAM_CSI_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_axi2apb_cam_csi_ipclkport_aclk", "dout_cam_csi_busp",
+	     GAT_CAM_AXI2APB_CAM_CSI_IPCLKPORT_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_csi_bus_d_cam_csi_ipclkport_clk__system__clk_csi0", "dout_cam_csi0_aclk",
+	     GAT_CAM_CSI_BUS_D_CAM_CSI_IPCLKPORT_CLK__SYSTEM__CLK_CSI0, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_csi_bus_d_cam_csi_ipclkport_clk__system__clk_csi1", "dout_cam_csi1_aclk",
+	     GAT_CAM_CSI_BUS_D_CAM_CSI_IPCLKPORT_CLK__SYSTEM__CLK_CSI1, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_csi_bus_d_cam_csi_ipclkport_clk__system__clk_csi2", "dout_cam_csi2_aclk",
+	     GAT_CAM_CSI_BUS_D_CAM_CSI_IPCLKPORT_CLK__SYSTEM__CLK_CSI2, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_csi_bus_d_cam_csi_ipclkport_clk__system__clk_soc_noc", "dout_cam_csi_busd",
+	     GAT_CAM_CSI_BUS_D_CAM_CSI_IPCLKPORT_CLK__SYSTEM__CLK_SOC_NOC, 21,
+	     CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_csi_bus_d_cam_csi_ipclkport_clk__system__noc", "dout_cam_csi_busd",
+	     GAT_CAM_CSI_BUS_D_CAM_CSI_IPCLKPORT_CLK__SYSTEM__NOC, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(CAM_CSI0_0_IPCLKPORT_I_ACLK, "cam_csi0_0_ipclkport_i_aclk", "dout_cam_csi0_aclk",
+	     GAT_CAM_CSI0_0_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_csi0_0_ipclkport_i_pclk", "dout_cam_csi_busp",
+	     GAT_CAM_CSI0_0_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(CAM_CSI0_1_IPCLKPORT_I_ACLK, "cam_csi0_1_ipclkport_i_aclk", "dout_cam_csi0_aclk",
+	     GAT_CAM_CSI0_1_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_csi0_1_ipclkport_i_pclk", "dout_cam_csi_busp",
+	     GAT_CAM_CSI0_1_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(CAM_CSI0_2_IPCLKPORT_I_ACLK, "cam_csi0_2_ipclkport_i_aclk", "dout_cam_csi0_aclk",
+	     GAT_CAM_CSI0_2_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_csi0_2_ipclkport_i_pclk", "dout_cam_csi_busp",
+	     GAT_CAM_CSI0_2_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(CAM_CSI0_3_IPCLKPORT_I_ACLK, "cam_csi0_3_ipclkport_i_aclk", "dout_cam_csi0_aclk",
+	     GAT_CAM_CSI0_3_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_csi0_3_ipclkport_i_pclk", "dout_cam_csi_busp",
+	     GAT_CAM_CSI0_3_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(CAM_CSI1_0_IPCLKPORT_I_ACLK, "cam_csi1_0_ipclkport_i_aclk", "dout_cam_csi1_aclk",
+	     GAT_CAM_CSI1_0_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_csi1_0_ipclkport_i_pclk", "dout_cam_csi_busp",
+	     GAT_CAM_CSI1_0_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(CAM_CSI1_1_IPCLKPORT_I_ACLK, "cam_csi1_1_ipclkport_i_aclk", "dout_cam_csi1_aclk",
+	     GAT_CAM_CSI1_1_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_csi1_1_ipclkport_i_pclk", "dout_cam_csi_busp",
+	     GAT_CAM_CSI1_1_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(CAM_CSI1_2_IPCLKPORT_I_ACLK, "cam_csi1_2_ipclkport_i_aclk", "dout_cam_csi1_aclk",
+	     GAT_CAM_CSI1_2_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_csi1_2_ipclkport_i_pclk", "dout_cam_csi_busp",
+	     GAT_CAM_CSI1_2_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(CAM_CSI1_3_IPCLKPORT_I_ACLK, "cam_csi1_3_ipclkport_i_aclk", "dout_cam_csi1_aclk",
+	     GAT_CAM_CSI1_3_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_csi1_3_ipclkport_i_pclk", "dout_cam_csi_busp",
+	     GAT_CAM_CSI1_3_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(CAM_CSI2_0_IPCLKPORT_I_ACLK, "cam_csi2_0_ipclkport_i_aclk", "dout_cam_csi2_aclk",
+	     GAT_CAM_CSI2_0_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_csi2_0_ipclkport_i_pclk", "dout_cam_csi_busp",
+	     GAT_CAM_CSI2_0_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(CAM_CSI2_1_IPCLKPORT_I_ACLK, "cam_csi2_1_ipclkport_i_aclk", "dout_cam_csi2_aclk",
+	     GAT_CAM_CSI2_1_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_csi2_1_ipclkport_i_pclk", "dout_cam_csi_busp",
+	     GAT_CAM_CSI2_1_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(CAM_CSI2_2_IPCLKPORT_I_ACLK, "cam_csi2_2_ipclkport_i_aclk", "dout_cam_csi2_aclk",
+	     GAT_CAM_CSI2_2_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_csi2_2_ipclkport_i_pclk", "dout_cam_csi_busp",
+	     GAT_CAM_CSI2_2_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(CAM_CSI2_3_IPCLKPORT_I_ACLK, "cam_csi2_3_ipclkport_i_aclk", "dout_cam_csi2_aclk",
+	     GAT_CAM_CSI2_3_IPCLKPORT_I_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_csi2_3_ipclkport_i_pclk", "dout_cam_csi_busp",
+	     GAT_CAM_CSI2_3_IPCLKPORT_I_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_ns_brdg_cam_csi_ipclkport_clk__psoc_cam_csi__clk_cam_csi_d",
+	     "dout_cam_csi_busd",
+	     GAT_CAM_NS_BRDG_CAM_CSI_IPCLKPORT_CLK__PSOC_CAM_CSI__CLK_CAM_CSI_D, 21,
+	     CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_ns_brdg_cam_csi_ipclkport_clk__psoc_cam_csi__clk_cam_csi_p",
+	     "dout_cam_csi_busp",
+	     GAT_CAM_NS_BRDG_CAM_CSI_IPCLKPORT_CLK__PSOC_CAM_CSI__CLK_CAM_CSI_P, 21,
+	     CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_sysreg_cam_csi_ipclkport_pclk", "dout_cam_csi_busp",
+	     GAT_CAM_SYSREG_CAM_CSI_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "cam_tbu_cam_csi_ipclkport_aclk", "dout_cam_csi_busd",
+	     GAT_CAM_TBU_CAM_CSI_IPCLKPORT_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+};
+
+static const struct samsung_cmu_info cam_csi_cmu_info __initconst = {
+	.pll_clks		= cam_csi_pll_clks,
+	.nr_pll_clks		= ARRAY_SIZE(cam_csi_pll_clks),
+	.mux_clks		= cam_csi_mux_clks,
+	.nr_mux_clks		= ARRAY_SIZE(cam_csi_mux_clks),
+	.div_clks		= cam_csi_div_clks,
+	.nr_div_clks		= ARRAY_SIZE(cam_csi_div_clks),
+	.gate_clks		= cam_csi_gate_clks,
+	.nr_gate_clks		= ARRAY_SIZE(cam_csi_gate_clks),
+	.nr_clk_ids		= CAM_CSI_NR_CLK,
+	.clk_regs		= cam_csi_clk_regs,
+	.nr_clk_regs		= ARRAY_SIZE(cam_csi_clk_regs),
+};
+
 /**
  * fsd_cmu_probe - Probe function for FSD platform clocks
  * @pdev: Pointer to platform device
@@ -1576,6 +1780,9 @@ static const struct of_device_id fsd_cmu_of_match[] = {
 	}, {
 		.compatible = "tesla,fsd-clock-mfc",
 		.data = &mfc_cmu_info,
+	}, {
+		.compatible = "tesla,fsd-clock-cam_csi",
+		.data = &cam_csi_cmu_info,
 	}, {
 	},
 };
-- 
2.25.1


^ permalink raw reply related

* [PATCH v5 08/16] clk: samsung: fsd: Add cmu_imem block clock information
From: Alim Akhtar @ 2022-01-24 14:16 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel
  Cc: soc, linux-clk, devicetree, olof, arnd, linus.walleij,
	catalin.marinas, robh+dt, krzysztof.kozlowski, s.nawrocki,
	linux-samsung-soc, pankaj.dubey, sboyd, Alim Akhtar, linux-fsd,
	Arjun K V, Tauseef Nomani
In-Reply-To: <20220124141644.71052-1-alim.akhtar@samsung.com>

Adds cmu_imem clock related code, imem block contains IPs
like WDT, DMA, TMU etc, these clocks are required for such
IP function.

Cc: linux-fsd@tesla.com
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
Signed-off-by: Arjun K V <arjun.kv@samsung.com>
Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
Signed-off-by: Tauseef Nomani <tauseef.n@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
---
 drivers/clk/samsung/clk-fsd.c | 283 ++++++++++++++++++++++++++++++++++
 1 file changed, 283 insertions(+)

diff --git a/drivers/clk/samsung/clk-fsd.c b/drivers/clk/samsung/clk-fsd.c
index 19c3ea35a6ea..f15b5b6b8eca 100644
--- a/drivers/clk/samsung/clk-fsd.c
+++ b/drivers/clk/samsung/clk-fsd.c
@@ -1144,6 +1144,289 @@ static const struct samsung_cmu_info fsys1_cmu_info __initconst = {
 	.clk_name		= "dout_cmu_fsys1_shared0div4",
 };
 
+/* Register Offset definitions for CMU_IMEM (0x10010000) */
+#define PLL_CON0_CLK_IMEM_ACLK				0x100
+#define PLL_CON0_CLK_IMEM_INTMEMCLK			0x120
+#define PLL_CON0_CLK_IMEM_TCUCLK			0x140
+#define DIV_OSCCLK_IMEM_TMUTSCLK			0x1800
+#define GAT_IMEM_IMEM_CMU_IMEM_IPCLKPORT_PCLK		0x2000
+#define GAT_IMEM_MCT_IPCLKPORT_OSCCLK__ALO		0x2004
+#define GAT_IMEM_OTP_CON_TOP_IPCLKPORT_I_OSCCLK		0x2008
+#define GAT_IMEM_RSTNSYNC_OSCCLK_IPCLKPORT_CLK		0x200c
+#define GAT_IMEM_TMU_CPU0_IPCLKPORT_I_CLK		0x2010
+#define GAT_IMEM_TMU_CPU0_IPCLKPORT_I_CLK_TS		0x2014
+#define GAT_IMEM_TMU_CPU2_IPCLKPORT_I_CLK		0x2018
+#define GAT_IMEM_TMU_CPU2_IPCLKPORT_I_CLK_TS		0x201c
+#define GAT_IMEM_TMU_GPU_IPCLKPORT_I_CLK		0x2020
+#define GAT_IMEM_TMU_GPU_IPCLKPORT_I_CLK_TS		0x2024
+#define GAT_IMEM_TMU_GT_IPCLKPORT_I_CLK			0x2028
+#define GAT_IMEM_TMU_GT_IPCLKPORT_I_CLK_TS		0x202c
+#define GAT_IMEM_TMU_TOP_IPCLKPORT_I_CLK		0x2030
+#define GAT_IMEM_TMU_TOP_IPCLKPORT_I_CLK_TS		0x2034
+#define GAT_IMEM_WDT0_IPCLKPORT_CLK			0x2038
+#define GAT_IMEM_WDT1_IPCLKPORT_CLK			0x203c
+#define GAT_IMEM_WDT2_IPCLKPORT_CLK			0x2040
+#define GAT_IMEM_ADM_AXI4ST_I0_IMEM_IPCLKPORT_ACLKM	0x2044
+#define GAT_IMEM_ADM_AXI4ST_I1_IMEM_IPCLKPORT_ACLKM	0x2048
+#define GAT_IMEM_ADM_AXI4ST_I2_IMEM_IPCLKPORT_ACLKM	0x204c
+#define GAT_IMEM_ADS_AXI4ST_I0_IMEM_IPCLKPORT_ACLKS	0x2050
+#define GAT_IMEM_ADS_AXI4ST_I1_IMEM_IPCLKPORT_ACLKS	0x2054
+#define GAT_IMEM_ADS_AXI4ST_I2_IMEM_IPCLKPORT_ACLKS	0x2058
+#define GAT_IMEM_ASYNC_DMA0_IPCLKPORT_PCLKM		0x205c
+#define GAT_IMEM_ASYNC_DMA0_IPCLKPORT_PCLKS		0x2060
+#define GAT_IMEM_ASYNC_DMA1_IPCLKPORT_PCLKM		0x2064
+#define GAT_IMEM_ASYNC_DMA1_IPCLKPORT_PCLKS		0x2068
+#define GAT_IMEM_AXI2APB_IMEMP0_IPCLKPORT_ACLK		0x206c
+#define GAT_IMEM_AXI2APB_IMEMP1_IPCLKPORT_ACLK		0x2070
+#define GAT_IMEM_BUS_D_IMEM_IPCLKPORT_MAINCLK		0x2074
+#define GAT_IMEM_BUS_P_IMEM_IPCLKPORT_MAINCLK		0x2078
+#define GAT_IMEM_BUS_P_IMEM_IPCLKPORT_PERICLK		0x207c
+#define GAT_IMEM_BUS_P_IMEM_IPCLKPORT_TCUCLK		0x2080
+#define GAT_IMEM_DMA0_IPCLKPORT_ACLK			0x2084
+#define GAT_IMEM_DMA1_IPCLKPORT_ACLK			0x2088
+#define GAT_IMEM_GIC500_INPUT_SYNC_IPCLKPORT_CLK	0x208c
+#define GAT_IMEM_GIC_IPCLKPORT_CLK			0x2090
+#define GAT_IMEM_INTMEM_IPCLKPORT_ACLK			0x2094
+#define GAT_IMEM_MAILBOX_SCS_CA72_IPCLKPORT_PCLK	0x2098
+#define GAT_IMEM_MAILBOX_SMS_CA72_IPCLKPORT_PCLK	0x209c
+#define GAT_IMEM_MCT_IPCLKPORT_PCLK			0x20a0
+#define GAT_IMEM_NS_BRDG_IMEM_IPCLKPORT_CLK__PSCO_IMEM__CLK_IMEM_D	0x20a4
+#define GAT_IMEM_NS_BRDG_IMEM_IPCLKPORT_CLK__PSCO_IMEM__CLK_IMEM_TCU	0x20a8
+#define GAT_IMEM_NS_BRDG_IMEM_IPCLKPORT_CLK__PSOC_IMEM__CLK_IMEM_P	0x20ac
+#define GAT_IMEM_OTP_CON_TOP_IPCLKPORT_PCLK		0x20b0
+#define GAT_IMEM_RSTNSYNC_ACLK_IPCLKPORT_CLK		0x20b4
+#define GAT_IMEM_RSTNSYNC_INTMEMCLK_IPCLKPORT_CLK	0x20b8
+#define GAT_IMEM_RSTNSYNC_TCUCLK_IPCLKPORT_CLK		0x20bc
+#define GAT_IMEM_SFRIF_TMU0_IMEM_IPCLKPORT_PCLK		0x20c0
+#define GAT_IMEM_SFRIF_TMU1_IMEM_IPCLKPORT_PCLK		0x20c4
+#define GAT_IMEM_SYSREG_IMEM_IPCLKPORT_PCLK		0x20c8
+#define GAT_IMEM_TBU_IMEM_IPCLKPORT_ACLK		0x20cc
+#define GAT_IMEM_TCU_IPCLKPORT_ACLK			0x20d0
+#define GAT_IMEM_WDT0_IPCLKPORT_PCLK			0x20d4
+#define GAT_IMEM_WDT1_IPCLKPORT_PCLK			0x20d8
+#define GAT_IMEM_WDT2_IPCLKPORT_PCLK			0x20dc
+
+static const unsigned long imem_clk_regs[] __initconst = {
+	PLL_CON0_CLK_IMEM_ACLK,
+	PLL_CON0_CLK_IMEM_INTMEMCLK,
+	PLL_CON0_CLK_IMEM_TCUCLK,
+	DIV_OSCCLK_IMEM_TMUTSCLK,
+	GAT_IMEM_IMEM_CMU_IMEM_IPCLKPORT_PCLK,
+	GAT_IMEM_MCT_IPCLKPORT_OSCCLK__ALO,
+	GAT_IMEM_OTP_CON_TOP_IPCLKPORT_I_OSCCLK,
+	GAT_IMEM_RSTNSYNC_OSCCLK_IPCLKPORT_CLK,
+	GAT_IMEM_TMU_CPU0_IPCLKPORT_I_CLK,
+	GAT_IMEM_TMU_CPU0_IPCLKPORT_I_CLK_TS,
+	GAT_IMEM_TMU_CPU2_IPCLKPORT_I_CLK,
+	GAT_IMEM_TMU_CPU2_IPCLKPORT_I_CLK_TS,
+	GAT_IMEM_TMU_GPU_IPCLKPORT_I_CLK,
+	GAT_IMEM_TMU_GPU_IPCLKPORT_I_CLK_TS,
+	GAT_IMEM_TMU_GT_IPCLKPORT_I_CLK,
+	GAT_IMEM_TMU_GT_IPCLKPORT_I_CLK_TS,
+	GAT_IMEM_TMU_TOP_IPCLKPORT_I_CLK,
+	GAT_IMEM_TMU_TOP_IPCLKPORT_I_CLK_TS,
+	GAT_IMEM_WDT0_IPCLKPORT_CLK,
+	GAT_IMEM_WDT1_IPCLKPORT_CLK,
+	GAT_IMEM_WDT2_IPCLKPORT_CLK,
+	GAT_IMEM_ADM_AXI4ST_I0_IMEM_IPCLKPORT_ACLKM,
+	GAT_IMEM_ADM_AXI4ST_I1_IMEM_IPCLKPORT_ACLKM,
+	GAT_IMEM_ADM_AXI4ST_I2_IMEM_IPCLKPORT_ACLKM,
+	GAT_IMEM_ADS_AXI4ST_I0_IMEM_IPCLKPORT_ACLKS,
+	GAT_IMEM_ADS_AXI4ST_I1_IMEM_IPCLKPORT_ACLKS,
+	GAT_IMEM_ADS_AXI4ST_I2_IMEM_IPCLKPORT_ACLKS,
+	GAT_IMEM_ASYNC_DMA0_IPCLKPORT_PCLKM,
+	GAT_IMEM_ASYNC_DMA0_IPCLKPORT_PCLKS,
+	GAT_IMEM_ASYNC_DMA1_IPCLKPORT_PCLKM,
+	GAT_IMEM_ASYNC_DMA1_IPCLKPORT_PCLKS,
+	GAT_IMEM_AXI2APB_IMEMP0_IPCLKPORT_ACLK,
+	GAT_IMEM_AXI2APB_IMEMP1_IPCLKPORT_ACLK,
+	GAT_IMEM_BUS_D_IMEM_IPCLKPORT_MAINCLK,
+	GAT_IMEM_BUS_P_IMEM_IPCLKPORT_MAINCLK,
+	GAT_IMEM_BUS_P_IMEM_IPCLKPORT_PERICLK,
+	GAT_IMEM_BUS_P_IMEM_IPCLKPORT_TCUCLK,
+	GAT_IMEM_DMA0_IPCLKPORT_ACLK,
+	GAT_IMEM_DMA1_IPCLKPORT_ACLK,
+	GAT_IMEM_GIC500_INPUT_SYNC_IPCLKPORT_CLK,
+	GAT_IMEM_GIC_IPCLKPORT_CLK,
+	GAT_IMEM_INTMEM_IPCLKPORT_ACLK,
+	GAT_IMEM_MAILBOX_SCS_CA72_IPCLKPORT_PCLK,
+	GAT_IMEM_MAILBOX_SMS_CA72_IPCLKPORT_PCLK,
+	GAT_IMEM_MCT_IPCLKPORT_PCLK,
+	GAT_IMEM_NS_BRDG_IMEM_IPCLKPORT_CLK__PSCO_IMEM__CLK_IMEM_D,
+	GAT_IMEM_NS_BRDG_IMEM_IPCLKPORT_CLK__PSCO_IMEM__CLK_IMEM_TCU,
+	GAT_IMEM_NS_BRDG_IMEM_IPCLKPORT_CLK__PSOC_IMEM__CLK_IMEM_P,
+	GAT_IMEM_OTP_CON_TOP_IPCLKPORT_PCLK,
+	GAT_IMEM_RSTNSYNC_ACLK_IPCLKPORT_CLK,
+	GAT_IMEM_RSTNSYNC_INTMEMCLK_IPCLKPORT_CLK,
+	GAT_IMEM_RSTNSYNC_TCUCLK_IPCLKPORT_CLK,
+	GAT_IMEM_SFRIF_TMU0_IMEM_IPCLKPORT_PCLK,
+	GAT_IMEM_SFRIF_TMU1_IMEM_IPCLKPORT_PCLK,
+	GAT_IMEM_SYSREG_IMEM_IPCLKPORT_PCLK,
+	GAT_IMEM_TBU_IMEM_IPCLKPORT_ACLK,
+	GAT_IMEM_TCU_IPCLKPORT_ACLK,
+	GAT_IMEM_WDT0_IPCLKPORT_PCLK,
+	GAT_IMEM_WDT1_IPCLKPORT_PCLK,
+	GAT_IMEM_WDT2_IPCLKPORT_PCLK,
+};
+
+PNAME(mout_imem_clk_imem_tcuclk_p) = { "fin_pll", "dout_cmu_imem_tcuclk" };
+PNAME(mout_imem_clk_imem_aclk_p) = { "fin_pll", "dout_cmu_imem_aclk" };
+PNAME(mout_imem_clk_imem_intmemclk_p) = { "fin_pll", "dout_cmu_imem_dmaclk" };
+
+static const struct samsung_mux_clock imem_mux_clks[] __initconst = {
+	MUX(0, "mout_imem_clk_imem_tcuclk", mout_imem_clk_imem_tcuclk_p,
+	    PLL_CON0_CLK_IMEM_TCUCLK, 4, 1),
+	MUX(0, "mout_imem_clk_imem_aclk", mout_imem_clk_imem_aclk_p, PLL_CON0_CLK_IMEM_ACLK, 4, 1),
+	MUX(0, "mout_imem_clk_imem_intmemclk", mout_imem_clk_imem_intmemclk_p,
+	    PLL_CON0_CLK_IMEM_INTMEMCLK, 4, 1),
+};
+
+static const struct samsung_div_clock imem_div_clks[] __initconst = {
+	DIV(0, "dout_imem_oscclk_imem_tmutsclk", "fin_pll", DIV_OSCCLK_IMEM_TMUTSCLK, 0, 4),
+};
+
+static const struct samsung_gate_clock imem_gate_clks[] __initconst = {
+	GATE(0, "imem_imem_cmu_imem_ipclkport_pclk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_IMEM_CMU_IMEM_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_otp_con_top_ipclkport_i_oscclk", "fin_pll",
+	     GAT_IMEM_OTP_CON_TOP_IPCLKPORT_I_OSCCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_tmu_top_ipclkport_i_clk", "fin_pll",
+	     GAT_IMEM_TMU_TOP_IPCLKPORT_I_CLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_tmu_gt_ipclkport_i_clk", "fin_pll",
+	     GAT_IMEM_TMU_GT_IPCLKPORT_I_CLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_tmu_cpu0_ipclkport_i_clk", "fin_pll",
+	     GAT_IMEM_TMU_CPU0_IPCLKPORT_I_CLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_tmu_gpu_ipclkport_i_clk", "fin_pll",
+	     GAT_IMEM_TMU_GPU_IPCLKPORT_I_CLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_mct_ipclkport_oscclk__alo", "fin_pll",
+	     GAT_IMEM_MCT_IPCLKPORT_OSCCLK__ALO, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_wdt0_ipclkport_clk", "fin_pll",
+	     GAT_IMEM_WDT0_IPCLKPORT_CLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_wdt1_ipclkport_clk", "fin_pll",
+	     GAT_IMEM_WDT1_IPCLKPORT_CLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_wdt2_ipclkport_clk", "fin_pll",
+	     GAT_IMEM_WDT2_IPCLKPORT_CLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(IMEM_TMU_CPU0_IPCLKPORT_I_CLK_TS, "imem_tmu_cpu0_ipclkport_i_clk_ts",
+	     "dout_imem_oscclk_imem_tmutsclk",
+	     GAT_IMEM_TMU_CPU0_IPCLKPORT_I_CLK_TS, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(IMEM_TMU_CPU2_IPCLKPORT_I_CLK_TS, "imem_tmu_cpu2_ipclkport_i_clk_ts",
+	     "dout_imem_oscclk_imem_tmutsclk",
+	     GAT_IMEM_TMU_CPU2_IPCLKPORT_I_CLK_TS, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(IMEM_TMU_GPU_IPCLKPORT_I_CLK_TS, "imem_tmu_gpu_ipclkport_i_clk_ts",
+	     "dout_imem_oscclk_imem_tmutsclk",
+	     GAT_IMEM_TMU_GPU_IPCLKPORT_I_CLK_TS, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(IMEM_TMU_GT_IPCLKPORT_I_CLK_TS, "imem_tmu_gt_ipclkport_i_clk_ts",
+	     "dout_imem_oscclk_imem_tmutsclk",
+	     GAT_IMEM_TMU_GT_IPCLKPORT_I_CLK_TS, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(IMEM_TMU_TOP_IPCLKPORT_I_CLK_TS, "imem_tmu_top_ipclkport_i_clk_ts",
+	     "dout_imem_oscclk_imem_tmutsclk",
+	     GAT_IMEM_TMU_TOP_IPCLKPORT_I_CLK_TS, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_adm_axi4st_i0_imem_ipclkport_aclkm", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_ADM_AXI4ST_I0_IMEM_IPCLKPORT_ACLKM, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_adm_axi4st_i1_imem_ipclkport_aclkm", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_ADM_AXI4ST_I1_IMEM_IPCLKPORT_ACLKM, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_adm_axi4st_i2_imem_ipclkport_aclkm", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_ADM_AXI4ST_I2_IMEM_IPCLKPORT_ACLKM, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_ads_axi4st_i0_imem_ipclkport_aclks", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_ADS_AXI4ST_I0_IMEM_IPCLKPORT_ACLKS, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_ads_axi4st_i1_imem_ipclkport_aclks", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_ADS_AXI4ST_I1_IMEM_IPCLKPORT_ACLKS, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_ads_axi4st_i2_imem_ipclkport_aclks", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_ADS_AXI4ST_I2_IMEM_IPCLKPORT_ACLKS, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_async_dma0_ipclkport_pclkm", "mout_imem_clk_imem_tcuclk",
+	     GAT_IMEM_ASYNC_DMA0_IPCLKPORT_PCLKM, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_async_dma0_ipclkport_pclks", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_ASYNC_DMA0_IPCLKPORT_PCLKS, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_async_dma1_ipclkport_pclkm", "mout_imem_clk_imem_tcuclk",
+	     GAT_IMEM_ASYNC_DMA1_IPCLKPORT_PCLKM, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_async_dma1_ipclkport_pclks", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_ASYNC_DMA1_IPCLKPORT_PCLKS, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_axi2apb_imemp0_ipclkport_aclk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_AXI2APB_IMEMP0_IPCLKPORT_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_axi2apb_imemp1_ipclkport_aclk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_AXI2APB_IMEMP1_IPCLKPORT_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_bus_d_imem_ipclkport_mainclk", "mout_imem_clk_imem_tcuclk",
+	     GAT_IMEM_BUS_D_IMEM_IPCLKPORT_MAINCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_bus_p_imem_ipclkport_mainclk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_BUS_P_IMEM_IPCLKPORT_MAINCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_bus_p_imem_ipclkport_pericclk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_BUS_P_IMEM_IPCLKPORT_PERICLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_bus_p_imem_ipclkport_tcuclk", "mout_imem_clk_imem_tcuclk",
+	     GAT_IMEM_BUS_P_IMEM_IPCLKPORT_TCUCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(IMEM_DMA0_IPCLKPORT_ACLK, "imem_dma0_ipclkport_aclk", "mout_imem_clk_imem_tcuclk",
+	     GAT_IMEM_DMA0_IPCLKPORT_ACLK, 21, CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0),
+	GATE(IMEM_DMA1_IPCLKPORT_ACLK, "imem_dma1_ipclkport_aclk", "mout_imem_clk_imem_tcuclk",
+	     GAT_IMEM_DMA1_IPCLKPORT_ACLK, 21, CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, 0),
+	GATE(0, "imem_gic500_input_sync_ipclkport_clk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_GIC500_INPUT_SYNC_IPCLKPORT_CLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_gic_ipclkport_clk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_GIC_IPCLKPORT_CLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_intmem_ipclkport_aclk", "mout_imem_clk_imem_intmemclk",
+	     GAT_IMEM_INTMEM_IPCLKPORT_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_mailbox_scs_ca72_ipclkport_pclk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_MAILBOX_SCS_CA72_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_mailbox_sms_ca72_ipclkport_pclk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_MAILBOX_SMS_CA72_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(IMEM_MCT_PCLK, "imem_mct_ipclkport_pclk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_MCT_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_ns_brdg_imem_ipclkport_clk__psco_imem__clk_imem_d",
+	     "mout_imem_clk_imem_tcuclk",
+	     GAT_IMEM_NS_BRDG_IMEM_IPCLKPORT_CLK__PSCO_IMEM__CLK_IMEM_D, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_ns_brdg_imem_ipclkport_clk__psco_imem__clk_imem_tcu",
+	     "mout_imem_clk_imem_tcuclk",
+	     GAT_IMEM_NS_BRDG_IMEM_IPCLKPORT_CLK__PSCO_IMEM__CLK_IMEM_TCU, 21,
+	     CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_ns_brdg_imem_ipclkport_clk__psoc_imem__clk_imem_p", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_NS_BRDG_IMEM_IPCLKPORT_CLK__PSOC_IMEM__CLK_IMEM_P, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_otp_con_top_ipclkport_pclk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_OTP_CON_TOP_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_rstnsync_aclk_ipclkport_clk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_RSTNSYNC_ACLK_IPCLKPORT_CLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_rstnsync_oscclk_ipclkport_clk", "fin_pll",
+	     GAT_IMEM_RSTNSYNC_OSCCLK_IPCLKPORT_CLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_rstnsync_intmemclk_ipclkport_clk", "mout_imem_clk_imem_intmemclk",
+	     GAT_IMEM_RSTNSYNC_INTMEMCLK_IPCLKPORT_CLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_rstnsync_tcuclk_ipclkport_clk", "mout_imem_clk_imem_tcuclk",
+	     GAT_IMEM_RSTNSYNC_TCUCLK_IPCLKPORT_CLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_sfrif_tmu0_imem_ipclkport_pclk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_SFRIF_TMU0_IMEM_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_sfrif_tmu1_imem_ipclkport_pclk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_SFRIF_TMU1_IMEM_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_tmu_cpu2_ipclkport_i_clk", "fin_pll",
+	     GAT_IMEM_TMU_CPU2_IPCLKPORT_I_CLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_sysreg_imem_ipclkport_pclk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_SYSREG_IMEM_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_tbu_imem_ipclkport_aclk", "mout_imem_clk_imem_tcuclk",
+	     GAT_IMEM_TBU_IMEM_IPCLKPORT_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(0, "imem_tcu_ipclkport_aclk", "mout_imem_clk_imem_tcuclk",
+	     GAT_IMEM_TCU_IPCLKPORT_ACLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(IMEM_WDT0_IPCLKPORT_PCLK, "imem_wdt0_ipclkport_pclk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_WDT0_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(IMEM_WDT1_IPCLKPORT_PCLK, "imem_wdt1_ipclkport_pclk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_WDT1_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+	GATE(IMEM_WDT2_IPCLKPORT_PCLK, "imem_wdt2_ipclkport_pclk", "mout_imem_clk_imem_aclk",
+	     GAT_IMEM_WDT2_IPCLKPORT_PCLK, 21, CLK_IGNORE_UNUSED, 0),
+};
+
+static const struct samsung_cmu_info imem_cmu_info __initconst = {
+	.mux_clks		= imem_mux_clks,
+	.nr_mux_clks		= ARRAY_SIZE(imem_mux_clks),
+	.div_clks		= imem_div_clks,
+	.nr_div_clks		= ARRAY_SIZE(imem_div_clks),
+	.gate_clks		= imem_gate_clks,
+	.nr_gate_clks		= ARRAY_SIZE(imem_gate_clks),
+	.nr_clk_ids		= IMEM_NR_CLK,
+	.clk_regs		= imem_clk_regs,
+	.nr_clk_regs		= ARRAY_SIZE(imem_clk_regs),
+};
+
+static void __init fsd_clk_imem_init(struct device_node *np)
+{
+	samsung_cmu_register_one(np, &imem_cmu_info);
+}
+
+CLK_OF_DECLARE(fsd_clk_imem, "tesla,fsd-clock-imem", fsd_clk_imem_init);
+
 /**
  * fsd_cmu_probe - Probe function for FSD platform clocks
  * @pdev: Pointer to platform device
-- 
2.25.1


^ permalink raw reply related

* [PATCH v5 11/16] dt-bindings: pinctrl: samsung: Add compatible for Tesla FSD SoC
From: Alim Akhtar @ 2022-01-24 14:16 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel
  Cc: soc, linux-clk, devicetree, olof, arnd, linus.walleij,
	catalin.marinas, robh+dt, krzysztof.kozlowski, s.nawrocki,
	linux-samsung-soc, pankaj.dubey, sboyd, Alim Akhtar, linux-fsd
In-Reply-To: <20220124141644.71052-1-alim.akhtar@samsung.com>

Add compatible for Tesla Full Self-Driving SoC. The
pinctrl hardware IP is similar to what found on most of the
Exynos series of SoC, so this new compatible is added in
Samsung pinctrl binding.

Cc: linux-fsd@tesla.com
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
---
 Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml
index 28f0851d07bb..989e48c051cf 100644
--- a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml
@@ -56,6 +56,7 @@ properties:
       - samsung,exynos7885-pinctrl
       - samsung,exynos850-pinctrl
       - samsung,exynosautov9-pinctrl
+      - tesla,fsd-pinctrl
 
   interrupts:
     description:
-- 
2.25.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox