Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v1 1/4] dt-bindings: input: Add Himax HX83102J touchscreen
From: Allen Lin @ 2024-03-26  5:46 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Rob Herring, dmitry.torokhov, krzysztof.kozlowski+dt, conor+dt,
	jikos, benjamin.tissoires, linux-input, devicetree, linux-kernel
In-Reply-To: <20240322-rectified-udder-fef9102f58da@spud>

Conor Dooley <conor@kernel.org> 於 2024年3月23日 週六 上午2:34寫道:
>
> On Fri, Mar 22, 2024 at 01:30:09PM -0500, Rob Herring wrote:
> > On Fri, Mar 22, 2024 at 05:54:08PM +0000, Conor Dooley wrote:
> > > On Fri, Mar 22, 2024 at 04:56:03PM +0800, Allen_Lin wrote:
> > > > Add the HX83102j touchscreen device tree bindings documents.
> > > > HX83102j is a Himax TDDI touchscreen controller.
> > > > It's power sequence should be bound with a lcm driver, thus it
> > > > needs to be a panel follower. Others are the same as normal SPI
> > > > touchscreen controller.
> > > >
> > > > Signed-off-by: Allen_Lin <allencl_lin@hotmail.com>
> > >
> > > note to self/Krzysztof/Rob:
> > > There was a previous attempt at this kind of device. This version looks
> > > better but might be incomplete given there's a bunch more properties in
> > > that patchset:
> > > https://lore.kernel.org/all/20231017091900.801989-1-tylor_yang@himax.corp-partner.google.com/
> >
> > Those don't look like properties we want coming back.
>
> Oh, I don't want most of them coming back either. There are some
> supplies in there though that I think we would like to come back, no?
> Maybe this particular device doesn't have any supplies, but that doesn't
> really seem credible.

We will use Firmware-name in Device Tree.
For power supply settings, because there may be other device using
same regulator.
We plan to define it as an optional property for user to control in
next release.

^ permalink raw reply

* RE: [PATCH v2 6/6] misc: pci_endpoint_test: Add Device ID for R-Car V4H PCIe controller
From: Yoshihiro Shimoda @ 2024-03-26  5:47 UTC (permalink / raw)
  To: Frank Li
  Cc: lpieralisi@kernel.org, kw@linux.com, robh@kernel.org,
	bhelgaas@google.com, krzysztof.kozlowski+dt@linaro.org,
	conor+dt@kernel.org, jingoohan1@gmail.com,
	gustavo.pimentel@synopsys.com, mani@kernel.org,
	marek.vasut+renesas@gmail.com, linux-pci@vger.kernel.org,
	devicetree@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
	Geert Uytterhoeven
In-Reply-To: <ZgI/IGe2L0rJ8SSF@lizhi-Precision-Tower-5810>

Hi Frank,

> From: Frank Li, Sent: Tuesday, March 26, 2024 12:21 PM
 
> On Tue, Mar 26, 2024 at 11:45:40AM +0900, Yoshihiro Shimoda wrote:
> > Add Renesas R8A779G0 in pci_device_id table so that pci-epf-test
> > can be used for testing PCIe EP on R-Car V4H.
> >
> > Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
> > Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> > ---
> >  drivers/misc/pci_endpoint_test.c | 4 ++++
> >  1 file changed, 4 insertions(+)
> >
> > diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
> > index c38a6083f0a7..2fa3c6473c7d 100644
> > --- a/drivers/misc/pci_endpoint_test.c
> > +++ b/drivers/misc/pci_endpoint_test.c
> > @@ -83,6 +83,7 @@
> >  #define PCI_DEVICE_ID_RENESAS_R8A774C0		0x002d
> >  #define PCI_DEVICE_ID_RENESAS_R8A774E1		0x0025
> >  #define PCI_DEVICE_ID_RENESAS_R8A779F0		0x0031
> > +#define PCI_DEVICE_ID_RENESAS_R8A779G0		0x0030
> >
> >  static DEFINE_IDA(pci_endpoint_test_ida);
> >
> > @@ -1005,6 +1006,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
> >  	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A779F0),
> >  	  .driver_data = (kernel_ulong_t)&default_data,
> >  	},
> > +	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A779G0),
> > +	  .driver_data = (kernel_ulong_t)&default_data,
> > +	},
> 
> You use default_data, why need new device_id? I think you can use 0x0031
> to do test.

I thought we can add a new device_id freely like other devices.
Since the PCIe controller's endpoint mode can configure the device id,
I can use 0x0031 to do test though.

If such a reusable entry exists, is adding a new device id into the driver prohibited?

Best regards,
Yoshihiro Shimoda

> Frank
> 
> >  	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
> >  	  .driver_data = (kernel_ulong_t)&j721e_data,
> >  	},
> > --
> > 2.25.1
> >

^ permalink raw reply

* [PATCH v4 0/1] Add StarFive JH8100 dwmac support
From: Tan Chun Hau @ 2024-03-26  5:25 UTC (permalink / raw)
  To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Rob Herring, Emil Renner Berthing, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Maxime Coquelin,
	Alexandre Torgue, Simon Horman, Bartosz Golaszewski,
	Andrew Halaney, Jisheng Zhang, Uwe Kleine-König,
	Russell King
  Cc: Ley Foon Tan, Jee Heng Sia, netdev, devicetree, linux-kernel,
	linux-stm32, linux-arm-kernel, linux-riscv

Add StarFive JH8100 dwmac support.
The JH8100 dwmac shares the same driver code as the JH7110 dwmac
and has only one reset signal.
    
Please refer to below:
    
  JH8100: reset-names = "stmmaceth";
  JH7110: reset-names = "stmmaceth", "ahb";
  JH7100: reset-names = "ahb";
    
Example usage of JH8100 in the device tree:
    
gmac0: ethernet@16030000 {
        compatible = "starfive,jh8100-dwmac",
                     "starfive,jh7110-dwmac",
                     "snps,dwmac-5.20";
        ...
};

Changes in v4:
- restructure content based on feedback received.

Tan Chun Hau (1):
  dt-bindings: net: starfive,jh7110-dwmac: Add StarFive JH8100 support

 .../devicetree/bindings/net/snps,dwmac.yaml   |  1 +
 .../bindings/net/starfive,jh7110-dwmac.yaml   | 54 ++++++++++++++-----
 2 files changed, 41 insertions(+), 14 deletions(-)

-- 
2.25.1


^ permalink raw reply

* 回复: [PATCH v2 2/2] ASoC: cdns: Add drivers of Cadence Multi-Channel I2S Controller
From: Xingyu Wu @ 2024-03-26  2:04 UTC (permalink / raw)
  To: Mark Brown, Pierre-Louis Bossart
  Cc: Liam Girdwood, Claudiu Beznea, Jaroslav Kysela, Takashi Iwai,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	alsa-devel@alsa-project.org, linux-sound@vger.kernel.org
In-Reply-To: <aeac0262-1054-4bc9-b5e9-653785305162@sirena.org.uk>

> 
> On Wed, Mar 20, 2024 at 10:00:24AM -0500, Pierre-Louis Bossart wrote:
> 
> > > +	for (i = 0; i < CDNS_I2S_FIFO_DEPTH; i++) {
> > > +		if (format == SNDRV_PCM_FORMAT_S16_LE) {
> > > +			data[0] = p16[tx_ptr][0];
> > > +			data[1] = p16[tx_ptr][1];
> > > +		} else if (format == SNDRV_PCM_FORMAT_S32_LE) {
> > > +			data[0] = p32[tx_ptr][0];
> > > +			data[1] = p32[tx_ptr][1];
> > > +		}
> 
> > what about other formats implied by the use of 'else if' ?
> 
> In general things like this should be written as switch statements.

OK, I will fix it in next version of this patch.

Thanks,
Xingyu Wu

^ permalink raw reply

* Re: [PATCH v5 1/3] dt-bindings: dmaengine: Add dmamux for CV18XX/SG200X series SoC
From: Inochi Amaoto @ 2024-03-26  3:49 UTC (permalink / raw)
  To: Frank Li, Inochi Amaoto
  Cc: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Chen Wang, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Jisheng Zhang, Liu Gui, Jingbao Qiu, dlan, dmaengine, devicetree,
	linux-kernel, linux-riscv
In-Reply-To: <ZgJDCL+aq3ZTE6/1@lizhi-Precision-Tower-5810>

On Mon, Mar 25, 2024 at 11:37:44PM -0400, Frank Li wrote:
> On Tue, Mar 26, 2024 at 09:47:03AM +0800, Inochi Amaoto wrote:
> > The DMA IP of Sophgo CV18XX/SG200X is based on a DW AXI CORE, with
> > an additional channel remap register located in the top system control
> > area. The DMA channel is exclusive to each core.
> > 
> > Add the dmamux binding for CV18XX/SG200X series SoC
> > 
> > Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
> > ---
> >  .../bindings/dma/sophgo,cv1800-dmamux.yaml    | 48 ++++++++++++++++
> >  include/dt-bindings/dma/cv1800-dma.h          | 55 +++++++++++++++++++
> 
> I remember checkpatch.pl require .h have seperate patch.
> 
> Frank

checkpatch.pl does not give warning like this.

> 
> >  2 files changed, 103 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
> >  create mode 100644 include/dt-bindings/dma/cv1800-dma.h
> > 
> > diff --git a/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml b/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
> > new file mode 100644
> > index 000000000000..d7256646ea26
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
> > @@ -0,0 +1,48 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/dma/sophgo,cv1800-dmamux.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Sophgo CV1800/SG200 Series DMA mux
> > +
> > +maintainers:
> > +  - Inochi Amaoto <inochiama@outlook.com>
> > +
> > +allOf:
> > +  - $ref: dma-router.yaml#
> > +
> > +properties:
> > +  compatible:
> > +    const: sophgo,cv1800-dmamux
> > +
> > +  reg:
> > +    items:
> > +      - description: DMA channal remapping register
> > +      - description: DMA channel interrupt mapping register
> > +
> 
> Look like driver have not use it.
> 

The driver uses syscon offset to access the registers. This dmamux is
a subdevice of syscon.
And this properity, suggested by Rob, is just used to keep DT complete.

> Frank
> 
> > +  '#dma-cells':
> > +    const: 2
> > +    description:
> > +      The first cells is device id. The second one is the cpu id.
> > +
> > +  dma-masters:
> > +    maxItems: 1
> > +
> > +  dma-requests:
> > +    const: 8
> > +
> > +required:
> > +  - '#dma-cells'
> > +  - dma-masters
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    dma-router {
> > +      compatible = "sophgo,cv1800-dmamux";
> > +      #dma-cells = <2>;
> > +      dma-masters = <&dmac>;
> > +      dma-requests = <8>;
> > +    };
> > diff --git a/include/dt-bindings/dma/cv1800-dma.h b/include/dt-bindings/dma/cv1800-dma.h
> > new file mode 100644
> > index 000000000000..3ce9dac25259
> > --- /dev/null
> > +++ b/include/dt-bindings/dma/cv1800-dma.h
> > @@ -0,0 +1,55 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
> > +
> > +#ifndef __DT_BINDINGS_DMA_CV1800_H__
> > +#define __DT_BINDINGS_DMA_CV1800_H__
> > +
> > +#define DMA_I2S0_RX		0
> > +#define DMA_I2S0_TX		1
> > +#define DMA_I2S1_RX		2
> > +#define DMA_I2S1_TX		3
> > +#define DMA_I2S2_RX		4
> > +#define DMA_I2S2_TX		5
> > +#define DMA_I2S3_RX		6
> > +#define DMA_I2S3_TX		7
> > +#define DMA_UART0_RX		8
> > +#define DMA_UART0_TX		9
> > +#define DMA_UART1_RX		10
> > +#define DMA_UART1_TX		11
> > +#define DMA_UART2_RX		12
> > +#define DMA_UART2_TX		13
> > +#define DMA_UART3_RX		14
> > +#define DMA_UART3_TX		15
> > +#define DMA_SPI0_RX		16
> > +#define DMA_SPI0_TX		17
> > +#define DMA_SPI1_RX		18
> > +#define DMA_SPI1_TX		19
> > +#define DMA_SPI2_RX		20
> > +#define DMA_SPI2_TX		21
> > +#define DMA_SPI3_RX		22
> > +#define DMA_SPI3_TX		23
> > +#define DMA_I2C0_RX		24
> > +#define DMA_I2C0_TX		25
> > +#define DMA_I2C1_RX		26
> > +#define DMA_I2C1_TX		27
> > +#define DMA_I2C2_RX		28
> > +#define DMA_I2C2_TX		29
> > +#define DMA_I2C3_RX		30
> > +#define DMA_I2C3_TX		31
> > +#define DMA_I2C4_RX		32
> > +#define DMA_I2C4_TX		33
> > +#define DMA_TDM0_RX		34
> > +#define DMA_TDM0_TX		35
> > +#define DMA_TDM1_RX		36
> > +#define DMA_AUDSRC		37
> > +#define DMA_SPI_NAND		38
> > +#define DMA_SPI_NOR		39
> > +#define DMA_UART4_RX		40
> > +#define DMA_UART4_TX		41
> > +#define DMA_SPI_NOR1		42
> > +
> > +#define DMA_CPU_A53		0
> > +#define DMA_CPU_C906_0		1
> > +#define DMA_CPU_C906_1		2
> > +
> > +
> > +#endif // __DT_BINDINGS_DMA_CV1800_H__
> > --
> > 2.44.0
> > 

^ permalink raw reply

* Re: [PATCH v5 1/3] dt-bindings: dmaengine: Add dmamux for CV18XX/SG200X series SoC
From: Frank Li @ 2024-03-26  3:37 UTC (permalink / raw)
  To: Inochi Amaoto
  Cc: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Chen Wang, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Jisheng Zhang, Liu Gui, Jingbao Qiu, dlan, dmaengine, devicetree,
	linux-kernel, linux-riscv
In-Reply-To: <IA1PR20MB4953E2937788D9D92C91ABBBBB352@IA1PR20MB4953.namprd20.prod.outlook.com>

On Tue, Mar 26, 2024 at 09:47:03AM +0800, Inochi Amaoto wrote:
> The DMA IP of Sophgo CV18XX/SG200X is based on a DW AXI CORE, with
> an additional channel remap register located in the top system control
> area. The DMA channel is exclusive to each core.
> 
> Add the dmamux binding for CV18XX/SG200X series SoC
> 
> Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
> ---
>  .../bindings/dma/sophgo,cv1800-dmamux.yaml    | 48 ++++++++++++++++
>  include/dt-bindings/dma/cv1800-dma.h          | 55 +++++++++++++++++++

I remember checkpatch.pl require .h have seperate patch.

Frank

>  2 files changed, 103 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
>  create mode 100644 include/dt-bindings/dma/cv1800-dma.h
> 
> diff --git a/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml b/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
> new file mode 100644
> index 000000000000..d7256646ea26
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
> @@ -0,0 +1,48 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/dma/sophgo,cv1800-dmamux.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Sophgo CV1800/SG200 Series DMA mux
> +
> +maintainers:
> +  - Inochi Amaoto <inochiama@outlook.com>
> +
> +allOf:
> +  - $ref: dma-router.yaml#
> +
> +properties:
> +  compatible:
> +    const: sophgo,cv1800-dmamux
> +
> +  reg:
> +    items:
> +      - description: DMA channal remapping register
> +      - description: DMA channel interrupt mapping register
> +

Look like driver have not use it.

Frank

> +  '#dma-cells':
> +    const: 2
> +    description:
> +      The first cells is device id. The second one is the cpu id.
> +
> +  dma-masters:
> +    maxItems: 1
> +
> +  dma-requests:
> +    const: 8
> +
> +required:
> +  - '#dma-cells'
> +  - dma-masters
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    dma-router {
> +      compatible = "sophgo,cv1800-dmamux";
> +      #dma-cells = <2>;
> +      dma-masters = <&dmac>;
> +      dma-requests = <8>;
> +    };
> diff --git a/include/dt-bindings/dma/cv1800-dma.h b/include/dt-bindings/dma/cv1800-dma.h
> new file mode 100644
> index 000000000000..3ce9dac25259
> --- /dev/null
> +++ b/include/dt-bindings/dma/cv1800-dma.h
> @@ -0,0 +1,55 @@
> +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
> +
> +#ifndef __DT_BINDINGS_DMA_CV1800_H__
> +#define __DT_BINDINGS_DMA_CV1800_H__
> +
> +#define DMA_I2S0_RX		0
> +#define DMA_I2S0_TX		1
> +#define DMA_I2S1_RX		2
> +#define DMA_I2S1_TX		3
> +#define DMA_I2S2_RX		4
> +#define DMA_I2S2_TX		5
> +#define DMA_I2S3_RX		6
> +#define DMA_I2S3_TX		7
> +#define DMA_UART0_RX		8
> +#define DMA_UART0_TX		9
> +#define DMA_UART1_RX		10
> +#define DMA_UART1_TX		11
> +#define DMA_UART2_RX		12
> +#define DMA_UART2_TX		13
> +#define DMA_UART3_RX		14
> +#define DMA_UART3_TX		15
> +#define DMA_SPI0_RX		16
> +#define DMA_SPI0_TX		17
> +#define DMA_SPI1_RX		18
> +#define DMA_SPI1_TX		19
> +#define DMA_SPI2_RX		20
> +#define DMA_SPI2_TX		21
> +#define DMA_SPI3_RX		22
> +#define DMA_SPI3_TX		23
> +#define DMA_I2C0_RX		24
> +#define DMA_I2C0_TX		25
> +#define DMA_I2C1_RX		26
> +#define DMA_I2C1_TX		27
> +#define DMA_I2C2_RX		28
> +#define DMA_I2C2_TX		29
> +#define DMA_I2C3_RX		30
> +#define DMA_I2C3_TX		31
> +#define DMA_I2C4_RX		32
> +#define DMA_I2C4_TX		33
> +#define DMA_TDM0_RX		34
> +#define DMA_TDM0_TX		35
> +#define DMA_TDM1_RX		36
> +#define DMA_AUDSRC		37
> +#define DMA_SPI_NAND		38
> +#define DMA_SPI_NOR		39
> +#define DMA_UART4_RX		40
> +#define DMA_UART4_TX		41
> +#define DMA_SPI_NOR1		42
> +
> +#define DMA_CPU_A53		0
> +#define DMA_CPU_C906_0		1
> +#define DMA_CPU_C906_1		2
> +
> +
> +#endif // __DT_BINDINGS_DMA_CV1800_H__
> --
> 2.44.0
> 

^ permalink raw reply

* Re: [PATCH v2 6/6] misc: pci_endpoint_test: Add Device ID for R-Car V4H PCIe controller
From: Frank Li @ 2024-03-26  3:21 UTC (permalink / raw)
  To: Yoshihiro Shimoda
  Cc: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
	jingoohan1, gustavo.pimentel, mani, marek.vasut+renesas,
	linux-pci, devicetree, linux-renesas-soc, Geert Uytterhoeven
In-Reply-To: <20240326024540.2336155-7-yoshihiro.shimoda.uh@renesas.com>

On Tue, Mar 26, 2024 at 11:45:40AM +0900, Yoshihiro Shimoda wrote:
> Add Renesas R8A779G0 in pci_device_id table so that pci-epf-test
> can be used for testing PCIe EP on R-Car V4H.
> 
> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
>  drivers/misc/pci_endpoint_test.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
> index c38a6083f0a7..2fa3c6473c7d 100644
> --- a/drivers/misc/pci_endpoint_test.c
> +++ b/drivers/misc/pci_endpoint_test.c
> @@ -83,6 +83,7 @@
>  #define PCI_DEVICE_ID_RENESAS_R8A774C0		0x002d
>  #define PCI_DEVICE_ID_RENESAS_R8A774E1		0x0025
>  #define PCI_DEVICE_ID_RENESAS_R8A779F0		0x0031
> +#define PCI_DEVICE_ID_RENESAS_R8A779G0		0x0030
>  
>  static DEFINE_IDA(pci_endpoint_test_ida);
>  
> @@ -1005,6 +1006,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
>  	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A779F0),
>  	  .driver_data = (kernel_ulong_t)&default_data,
>  	},
> +	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A779G0),
> +	  .driver_data = (kernel_ulong_t)&default_data,
> +	},

You use default_data, why need new device_id? I think you can use 0x0031
to do test.

Frank

>  	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
>  	  .driver_data = (kernel_ulong_t)&j721e_data,
>  	},
> -- 
> 2.25.1
> 

^ permalink raw reply

* [PATCH v2 5/6] PCI: dwc: rcar-gen4: Add support for other R-Car Gen4 PCIe controller
From: Yoshihiro Shimoda @ 2024-03-26  2:45 UTC (permalink / raw)
  To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
	jingoohan1, gustavo.pimentel, mani
  Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
	Yoshihiro Shimoda
In-Reply-To: <20240326024540.2336155-1-yoshihiro.shimoda.uh@renesas.com>

The PCIe controllers of R-Car V4H (r8a779g0) and one more SoC require
different initializing settings than R-Car S4-8 (r8a779f0). So, add
specific functions for them as "renesas,rcar-gen4-pcie{-ep}" compatible.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
 drivers/pci/controller/dwc/pcie-rcar-gen4.c | 188 +++++++++++++++++++-
 1 file changed, 187 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index a37613dd9ff4..7f3b5e9ca405 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -5,8 +5,10 @@
  */
 
 #include <linux/delay.h>
+#include <linux/firmware.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/pci.h>
@@ -20,9 +22,10 @@
 /* Renesas-specific */
 /* PCIe Mode Setting Register 0 */
 #define PCIEMSR0		0x0000
-#define BIFUR_MOD_SET_ON	BIT(0)
+#define APP_SRIS_MODE		BIT(6)
 #define DEVICE_TYPE_EP		0
 #define DEVICE_TYPE_RC		BIT(4)
+#define BIFUR_MOD_SET_ON	BIT(0)
 
 /* PCIe Interrupt Status 0 */
 #define PCIEINTSTS0		0x0084
@@ -37,33 +40,179 @@
 #define PCIEDMAINTSTSEN		0x0314
 #define PCIEDMAINTSTSEN_INIT	GENMASK(15, 0)
 
+/* Port Logic Registers 89 */
+#define PRTLGC89		0x0b70
+
+/* Port Logic Registers 90 */
+#define PRTLGC90		0x0b74
+
 /* PCIe Reset Control Register 1 */
 #define PCIERSTCTRL1		0x0014
 #define APP_HOLD_PHY_RST	BIT(16)
 #define APP_LTSSM_ENABLE	BIT(0)
 
+/* PCIe Power Management Control */
+#define PCIEPWRMNGCTRL		0x0070
+#define APP_CLK_REQ_N		BIT(11)
+#define APP_CLK_PM_EN		BIT(10)
+
 #define RCAR_NUM_SPEED_CHANGE_RETRIES	10
 #define RCAR_MAX_LINK_SPEED		4
 
 #define RCAR_GEN4_PCIE_EP_FUNC_DBI_OFFSET	0x1000
 #define RCAR_GEN4_PCIE_EP_FUNC_DBI2_OFFSET	0x800
 
+#define RCAR_GEN4_PCIE_FIRMEARE_NAME		"rcar_gen4_pcie.bin"
+#define RCAR_GEN4_PCIE_FIRMEARE_BASE_ADDR	0xc000
+
 struct rcar_gen4_pcie {
 	struct dw_pcie dw;
 	void __iomem *base;
+	/*
+	 * The R-Car Gen4 documents don't describe the PHY registers' name.
+	 * But, the initialization procedure describes these offsets. So,
+	 * this driver has "phy_base + magical offset number" for it.
+	 */
+	void __iomem *phy_base;
 	struct platform_device *pdev;
 	enum dw_pcie_device_mode mode;
 
 	int (*start_link_enable)(struct rcar_gen4_pcie *rcar);
+	void (*additional_common_init)(struct rcar_gen4_pcie *rcar);
 };
 #define to_rcar_gen4_pcie(_dw)	container_of(_dw, struct rcar_gen4_pcie, dw)
 
 struct rcar_gen4_pcie_platdata {
 	enum dw_pcie_device_mode mode;
 	int (*start_link_enable)(struct rcar_gen4_pcie *rcar);
+	void (*additional_common_init)(struct rcar_gen4_pcie *rcar);
 };
 
 /* Common */
+static void rcar_gen4_pcie_phy_reg_update_bits(struct rcar_gen4_pcie *rcar,
+					       u32 offset, u32 mask, u32 val)
+{
+	u32 tmp;
+
+	tmp = readl(rcar->phy_base + offset);
+	tmp &= ~mask;
+	tmp |= val;
+	writel(tmp, rcar->phy_base + offset);
+}
+
+static int rcar_gen4_pcie_reg_check_bit(struct rcar_gen4_pcie *rcar,
+					u32 offset, u32 mask)
+{
+	struct dw_pcie *dw = &rcar->dw;
+
+	if (dw_pcie_readl_dbi(dw, offset) & mask)
+		return -EAGAIN;
+
+	return 0;
+}
+
+static int rcar_gen4_pcie_update_phy_firmware(struct rcar_gen4_pcie *rcar)
+{
+	const u32 check_addr[] = { 0x00101018, 0x00101118, 0x00101021, 0x00101121};
+	struct dw_pcie *dw = &rcar->dw;
+	const struct firmware *fw;
+	unsigned int i, timeout;
+	u32 data;
+	int ret;
+
+	ret = request_firmware(&fw, RCAR_GEN4_PCIE_FIRMEARE_NAME, dw->dev);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < (fw->size / 2); i++) {
+		data = fw->data[i * 2] | fw->data[(i * 2) + 1] << 8;
+		timeout = 100;
+retry_data:
+		dw_pcie_writel_dbi(dw, PRTLGC89, RCAR_GEN4_PCIE_FIRMEARE_BASE_ADDR + i);
+		dw_pcie_writel_dbi(dw, PRTLGC90, data);
+		if (rcar_gen4_pcie_reg_check_bit(rcar, PRTLGC89, BIT(30)) < 0) {
+			if (!(--timeout)) {
+				ret = -ETIMEDOUT;
+				goto exit;
+			}
+			usleep_range(100, 200);
+			goto retry_data;
+		}
+	}
+
+	rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x0f8, BIT(17), BIT(17));
+
+	for (i = 0; i < ARRAY_SIZE(check_addr); i++) {
+		timeout = 100;
+retry_check:
+		dw_pcie_writel_dbi(dw, PRTLGC89, check_addr[i]);
+		ret = rcar_gen4_pcie_reg_check_bit(rcar, PRTLGC89, BIT(30));
+		ret |= rcar_gen4_pcie_reg_check_bit(rcar, PRTLGC90, BIT(0));
+		if (ret < 0) {
+			if (!(--timeout)) {
+				ret = -ETIMEDOUT;
+				goto exit;
+			}
+			usleep_range(100, 200);
+			goto retry_check;
+		}
+	}
+
+	ret = 0;
+exit:
+	release_firmware(fw);
+
+	return ret;
+}
+
+static int rcar_gen4_pcie_enable_phy(struct rcar_gen4_pcie *rcar)
+{
+	struct dw_pcie *dw = &rcar->dw;
+	u32 val;
+	int ret;
+
+	val = dw_pcie_readl_dbi(dw, PCIE_PORT_FORCE);
+	val |= PORT_FORCE_DO_DESKEW_FOR_SRIS;
+	dw_pcie_writel_dbi(dw, PCIE_PORT_FORCE, val);
+
+	val = readl(rcar->base + PCIEMSR0);
+	val |= APP_SRIS_MODE;
+	writel(val, rcar->base + PCIEMSR0);
+
+	rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x700, BIT(28), 0);
+	rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x700, BIT(20), 0);
+	rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x700, BIT(12), 0);
+	rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x700, BIT(4), 0);
+
+	rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x148, GENMASK(23, 22), BIT(22));
+	rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x148, GENMASK(18, 16), GENMASK(17, 16));
+	rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x148, GENMASK(7, 6), BIT(6));
+	rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x148, GENMASK(2, 0), GENMASK(11, 0));
+	rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x1d4, GENMASK(16, 15), GENMASK(16, 15));
+	rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x514, BIT(26), BIT(26));
+	rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x0f8, BIT(16), 0);
+	rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x0f8, BIT(19), BIT(19));
+
+	val = readl(rcar->base + PCIERSTCTRL1);
+	val &= ~APP_HOLD_PHY_RST;
+	writel(val, rcar->base + PCIERSTCTRL1);
+
+	ret = readl_poll_timeout(rcar->phy_base + 0x0f8, val, !(val & BIT(18)),
+				 100, 10000);
+	if (ret < 0)
+		return ret;
+
+	ret = rcar_gen4_pcie_update_phy_firmware(rcar);
+	if (ret)
+		return ret;
+
+	val = readl(rcar->base + PCIERSTCTRL1);
+	val |= APP_LTSSM_ENABLE;
+	writel(val, rcar->base + PCIERSTCTRL1);
+
+	return 0;
+}
+
 static void rcar_gen4_pcie_ltssm_enable(struct rcar_gen4_pcie *rcar,
 					bool enable)
 {
@@ -201,6 +350,9 @@ static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar)
 	if (ret)
 		goto err_unprepare;
 
+	if (rcar->additional_common_init)
+		rcar->additional_common_init(rcar);
+
 	return 0;
 
 err_unprepare:
@@ -242,6 +394,10 @@ static void rcar_gen4_pcie_unprepare(struct rcar_gen4_pcie *rcar)
 
 static int rcar_gen4_pcie_get_resources(struct rcar_gen4_pcie *rcar)
 {
+	rcar->phy_base = devm_platform_ioremap_resource_byname(rcar->pdev, "phy");
+	if (IS_ERR(rcar->phy_base))
+		return PTR_ERR(rcar->base);
+
 	/* Renesas-specific registers */
 	rcar->base = devm_platform_ioremap_resource_byname(rcar->pdev, "app");
 
@@ -452,6 +608,7 @@ static int rcar_gen4_add_dw_pcie(struct rcar_gen4_pcie *rcar)
 
 	rcar->mode = pd->mode;
 	rcar->start_link_enable = pd->start_link_enable;
+	rcar->additional_common_init = pd->additional_common_init;
 
 	switch (rcar->mode) {
 	case DW_PCIE_RC_TYPE:
@@ -521,6 +678,31 @@ static int r8a779f0_pcie_start_link_enable(struct rcar_gen4_pcie *rcar)
 	return 0;
 }
 
+static int rcar_gen4_pcie_start_link_enable(struct rcar_gen4_pcie *rcar)
+{
+	return rcar_gen4_pcie_enable_phy(rcar);
+}
+
+static void rcar_gen4_pcie_additional_common_init(struct rcar_gen4_pcie *rcar)
+{
+	struct dw_pcie *dw = &rcar->dw;
+	u32 val;
+
+	/*
+	 * The SoC manual said the register setting is required. Otherwise,
+	 * linkup failed.
+	 */
+	val = dw_pcie_readl_dbi(dw, PCIE_PORT_LANE_SKEW);
+	val &= ~PORT_LANE_SKEW_INSERT_MASK;
+	if (dw->num_lanes < 4)
+		val |= BIT(6);
+	dw_pcie_writel_dbi(dw, PCIE_PORT_LANE_SKEW, val);
+
+	val = readl(rcar->base + PCIEPWRMNGCTRL);
+	val |= APP_CLK_REQ_N | APP_CLK_PM_EN;
+	writel(val, rcar->base + PCIEPWRMNGCTRL);
+}
+
 static struct rcar_gen4_pcie_platdata platdata_r8a779f0_pcie = {
 	.mode = DW_PCIE_RC_TYPE,
 	.start_link_enable = r8a779f0_pcie_start_link_enable,
@@ -533,10 +715,14 @@ static struct rcar_gen4_pcie_platdata platdata_r8a779f0_pcie_ep = {
 
 static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie = {
 	.mode = DW_PCIE_RC_TYPE,
+	.start_link_enable = rcar_gen4_pcie_start_link_enable,
+	.additional_common_init = rcar_gen4_pcie_additional_common_init,
 };
 
 static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie_ep = {
 	.mode = DW_PCIE_EP_TYPE,
+	.start_link_enable = rcar_gen4_pcie_start_link_enable,
+	.additional_common_init = rcar_gen4_pcie_additional_common_init,
 };
 
 static const struct of_device_id rcar_gen4_pcie_of_match[] = {
-- 
2.25.1


^ permalink raw reply related

* [PATCH v2 6/6] misc: pci_endpoint_test: Add Device ID for R-Car V4H PCIe controller
From: Yoshihiro Shimoda @ 2024-03-26  2:45 UTC (permalink / raw)
  To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
	jingoohan1, gustavo.pimentel, mani
  Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
	Yoshihiro Shimoda, Geert Uytterhoeven
In-Reply-To: <20240326024540.2336155-1-yoshihiro.shimoda.uh@renesas.com>

Add Renesas R8A779G0 in pci_device_id table so that pci-epf-test
can be used for testing PCIe EP on R-Car V4H.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 drivers/misc/pci_endpoint_test.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index c38a6083f0a7..2fa3c6473c7d 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -83,6 +83,7 @@
 #define PCI_DEVICE_ID_RENESAS_R8A774C0		0x002d
 #define PCI_DEVICE_ID_RENESAS_R8A774E1		0x0025
 #define PCI_DEVICE_ID_RENESAS_R8A779F0		0x0031
+#define PCI_DEVICE_ID_RENESAS_R8A779G0		0x0030
 
 static DEFINE_IDA(pci_endpoint_test_ida);
 
@@ -1005,6 +1006,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A779F0),
 	  .driver_data = (kernel_ulong_t)&default_data,
 	},
+	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A779G0),
+	  .driver_data = (kernel_ulong_t)&default_data,
+	},
 	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
 	  .driver_data = (kernel_ulong_t)&j721e_data,
 	},
-- 
2.25.1


^ permalink raw reply related

* [PATCH v2 4/6] PCI: dwc: rcar-gen4: Add a new function pointer for other SoC support
From: Yoshihiro Shimoda @ 2024-03-26  2:45 UTC (permalink / raw)
  To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
	jingoohan1, gustavo.pimentel, mani
  Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
	Yoshihiro Shimoda
In-Reply-To: <20240326024540.2336155-1-yoshihiro.shimoda.uh@renesas.com>

This driver can reuse other R-Car Gen4 SoC support. However, some
initializing settings differs between r8a779f0 and others. So, add
a new function pointer start_link_enable() to support other R-Car
Gen4 SoC in the future. No behavior changes.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
 drivers/pci/controller/dwc/pcie-rcar-gen4.c | 57 +++++++++++++++++++--
 1 file changed, 52 insertions(+), 5 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index 0be760ed420b..a37613dd9ff4 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -53,9 +53,16 @@ struct rcar_gen4_pcie {
 	void __iomem *base;
 	struct platform_device *pdev;
 	enum dw_pcie_device_mode mode;
+
+	int (*start_link_enable)(struct rcar_gen4_pcie *rcar);
 };
 #define to_rcar_gen4_pcie(_dw)	container_of(_dw, struct rcar_gen4_pcie, dw)
 
+struct rcar_gen4_pcie_platdata {
+	enum dw_pcie_device_mode mode;
+	int (*start_link_enable)(struct rcar_gen4_pcie *rcar);
+};
+
 /* Common */
 static void rcar_gen4_pcie_ltssm_enable(struct rcar_gen4_pcie *rcar,
 					bool enable)
@@ -123,9 +130,13 @@ static int rcar_gen4_pcie_speed_change(struct dw_pcie *dw)
 static int rcar_gen4_pcie_start_link(struct dw_pcie *dw)
 {
 	struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
-	int i, changes;
+	int i, changes, ret;
 
-	rcar_gen4_pcie_ltssm_enable(rcar, true);
+	if (rcar->start_link_enable) {
+		ret = rcar->start_link_enable(rcar);
+		if (ret)
+			return ret;
+	}
 
 	/*
 	 * Require direct speed change with retrying here if the link_gen is
@@ -437,7 +448,10 @@ static void rcar_gen4_remove_dw_pcie_ep(struct rcar_gen4_pcie *rcar)
 /* Common */
 static int rcar_gen4_add_dw_pcie(struct rcar_gen4_pcie *rcar)
 {
-	rcar->mode = (uintptr_t)of_device_get_match_data(&rcar->pdev->dev);
+	const struct rcar_gen4_pcie_platdata *pd = of_device_get_match_data(&rcar->pdev->dev);
+
+	rcar->mode = pd->mode;
+	rcar->start_link_enable = pd->start_link_enable;
 
 	switch (rcar->mode) {
 	case DW_PCIE_RC_TYPE:
@@ -500,14 +514,47 @@ static void rcar_gen4_pcie_remove(struct platform_device *pdev)
 	rcar_gen4_pcie_unprepare(rcar);
 }
 
+static int r8a779f0_pcie_start_link_enable(struct rcar_gen4_pcie *rcar)
+{
+	rcar_gen4_pcie_ltssm_enable(rcar, true);
+
+	return 0;
+}
+
+static struct rcar_gen4_pcie_platdata platdata_r8a779f0_pcie = {
+	.mode = DW_PCIE_RC_TYPE,
+	.start_link_enable = r8a779f0_pcie_start_link_enable,
+};
+
+static struct rcar_gen4_pcie_platdata platdata_r8a779f0_pcie_ep = {
+	.mode = DW_PCIE_EP_TYPE,
+	.start_link_enable = r8a779f0_pcie_start_link_enable,
+};
+
+static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie = {
+	.mode = DW_PCIE_RC_TYPE,
+};
+
+static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie_ep = {
+	.mode = DW_PCIE_EP_TYPE,
+};
+
 static const struct of_device_id rcar_gen4_pcie_of_match[] = {
+	{
+		.compatible = "renesas,r8a779f0-pcie",
+		.data = &platdata_r8a779f0_pcie,
+	},
+	{
+		.compatible = "renesas,r8a779f0-pcie-ep",
+		.data = &platdata_r8a779f0_pcie_ep,
+	},
 	{
 		.compatible = "renesas,rcar-gen4-pcie",
-		.data = (void *)DW_PCIE_RC_TYPE,
+		.data = &platdata_rcar_gen4_pcie,
 	},
 	{
 		.compatible = "renesas,rcar-gen4-pcie-ep",
-		.data = (void *)DW_PCIE_EP_TYPE,
+		.data = &platdata_rcar_gen4_pcie_ep,
 	},
 	{},
 };
-- 
2.25.1


^ permalink raw reply related

* [PATCH v2 2/6] dt-bindings: PCI: rcar-gen4-pci-ep: Add R-Car V4H compatible
From: Yoshihiro Shimoda @ 2024-03-26  2:45 UTC (permalink / raw)
  To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
	jingoohan1, gustavo.pimentel, mani
  Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
	Yoshihiro Shimoda, Conor Dooley, Geert Uytterhoeven
In-Reply-To: <20240326024540.2336155-1-yoshihiro.shimoda.uh@renesas.com>

Document bindings for R-Car V4H (R8A779G0) PCIe endpoint module.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml b/Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml
index fe38f62da066..91b81ac75592 100644
--- a/Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml
+++ b/Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml
@@ -16,7 +16,9 @@ allOf:
 properties:
   compatible:
     items:
-      - const: renesas,r8a779f0-pcie-ep   # R-Car S4-8
+      - enum:
+          - renesas,r8a779f0-pcie-ep      # R-Car S4-8
+          - renesas,r8a779g0-pcie-ep      # R-Car V4H
       - const: renesas,rcar-gen4-pcie-ep  # R-Car Gen4
 
   reg:
-- 
2.25.1


^ permalink raw reply related

* [PATCH v2 3/6] PCI: dwc: Add PCIE_PORT_{FORCE,LANE_SKEW} macros
From: Yoshihiro Shimoda @ 2024-03-26  2:45 UTC (permalink / raw)
  To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
	jingoohan1, gustavo.pimentel, mani
  Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
	Yoshihiro Shimoda
In-Reply-To: <20240326024540.2336155-1-yoshihiro.shimoda.uh@renesas.com>

R-Car Gen4 PCIe controller needs to use the Synopsys-specific PCIe
configuration registers. So, add the macros.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
 drivers/pci/controller/dwc/pcie-designware.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 26dae4837462..aa4db6eaf02a 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -71,6 +71,9 @@
 #define LINK_WAIT_IATU			9
 
 /* Synopsys-specific PCIe configuration registers */
+#define PCIE_PORT_FORCE			0x708
+#define PORT_FORCE_DO_DESKEW_FOR_SRIS	BIT(23)
+
 #define PCIE_PORT_AFR			0x70C
 #define PORT_AFR_N_FTS_MASK		GENMASK(15, 8)
 #define PORT_AFR_N_FTS(n)		FIELD_PREP(PORT_AFR_N_FTS_MASK, n)
@@ -92,6 +95,9 @@
 #define PORT_LINK_MODE_4_LANES		PORT_LINK_MODE(0x7)
 #define PORT_LINK_MODE_8_LANES		PORT_LINK_MODE(0xf)
 
+#define PCIE_PORT_LANE_SKEW		0x714
+#define PORT_LANE_SKEW_INSERT_MASK	GENMASK(23, 0)
+
 #define PCIE_PORT_DEBUG0		0x728
 #define PORT_LOGIC_LTSSM_STATE_MASK	0x1f
 #define PORT_LOGIC_LTSSM_STATE_L0	0x11
-- 
2.25.1


^ permalink raw reply related

* [PATCH v2 1/6] dt-bindings: PCI: rcar-gen4-pci-host: Add R-Car V4H compatible
From: Yoshihiro Shimoda @ 2024-03-26  2:45 UTC (permalink / raw)
  To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
	jingoohan1, gustavo.pimentel, mani
  Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
	Yoshihiro Shimoda, Conor Dooley, Geert Uytterhoeven
In-Reply-To: <20240326024540.2336155-1-yoshihiro.shimoda.uh@renesas.com>

Document bindings for R-Car V4H (R8A779G0) PCIe host module.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
 Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml b/Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml
index ffb34339b637..955c664f1fbb 100644
--- a/Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml
+++ b/Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml
@@ -16,7 +16,9 @@ allOf:
 properties:
   compatible:
     items:
-      - const: renesas,r8a779f0-pcie   # R-Car S4-8
+      - enum:
+          - renesas,r8a779f0-pcie      # R-Car S4-8
+          - renesas,r8a779g0-pcie      # R-Car V4H
       - const: renesas,rcar-gen4-pcie  # R-Car Gen4
 
   reg:
-- 
2.25.1


^ permalink raw reply related

* [PATCH v2 0/6] PCI: dwc: rcar-gen4: Add R-Car V4H support
From: Yoshihiro Shimoda @ 2024-03-26  2:45 UTC (permalink / raw)
  To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
	jingoohan1, gustavo.pimentel, mani
  Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
	Yoshihiro Shimoda

The pcie-rcar-gen4 driver can reuse other R-Car Gen4 support. However,
some initializing settings differs between R-Car S4-8 (r8a779f0) and
others. The R-Car S4-8 will be minority about the setting way. So,
R-Car V4H will be majority and this is generic initialization way
as "renesas,rcar-gen4-pcie{-ep}" compatible. For now, I tested
both R-Car S4-8 and R-Car V4H on this driver. I'll support one more
other SoC (R-Car V4M) in the future.

Changes from v1:
https://lore.kernel.org/linux-pci/20240229120719.2553638-1-yoshihiro.shimoda.uh@renesas.com/
- Based on v6.9-rc1.
- Add Acked-by and/or Reviewed-by in patch [126/6].

Yoshihiro Shimoda (6):
  dt-bindings: PCI: rcar-gen4-pci-host: Add R-Car V4H compatible
  dt-bindings: PCI: rcar-gen4-pci-ep: Add R-Car V4H compatible
  PCI: dwc: Add PCIE_PORT_{FORCE,LANE_SKEW} macros
  PCI: dwc: rcar-gen4: Add a new function pointer for other SoC support
  PCI: dwc: rcar-gen4: Add support for other R-Car Gen4 PCIe controller
  misc: pci_endpoint_test: Add Device ID for R-Car V4H PCIe controller

 .../bindings/pci/rcar-gen4-pci-ep.yaml        |   4 +-
 .../bindings/pci/rcar-gen4-pci-host.yaml      |   4 +-
 drivers/misc/pci_endpoint_test.c              |   4 +
 drivers/pci/controller/dwc/pcie-designware.h  |   6 +
 drivers/pci/controller/dwc/pcie-rcar-gen4.c   | 245 +++++++++++++++++-
 5 files changed, 255 insertions(+), 8 deletions(-)

-- 
2.25.1


^ permalink raw reply

* [PATCH 2/2] usb: dwc2: add support for Sophgo CV18XX/SG200X series SoC
From: Inochi Amaoto @ 2024-03-26  2:37 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Minas Harutyunyan, Paul Walmsley, Palmer Dabbelt,
	Albert Ou
  Cc: Chen Wang, Liu Gui, Inochi Amaoto, linux-usb, devicetree,
	linux-kernel, linux-riscv
In-Reply-To: <IA1PR20MB49537ED844CEBF19880326CEBB352@IA1PR20MB4953.namprd20.prod.outlook.com>

Add params for DWC2 IP in Sophgo CV18XX/SG200X series SoC.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
---
 drivers/usb/dwc2/params.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index eb677c3cfd0b..171fcb34eb75 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -201,6 +201,25 @@ static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg)
 	p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT;
 }

+static void dwc2_set_cv1800_params(struct dwc2_hsotg *hsotg)
+{
+	struct dwc2_core_params *p = &hsotg->params;
+
+	p->otg_caps.hnp_support = false;
+	p->otg_caps.srp_support = false;
+	p->host_dma = false;
+	p->g_dma = false;
+	p->speed = DWC2_SPEED_PARAM_HIGH;
+	p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI;
+	p->phy_utmi_width = 16;
+	p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT;
+	p->lpm = false;
+	p->lpm_clock_gating = false;
+	p->besl = false;
+	p->hird_threshold_en = false;
+	p->power_down = DWC2_POWER_DOWN_PARAM_NONE;
+}
+
 static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
 {
 	struct dwc2_core_params *p = &hsotg->params;
@@ -295,6 +314,8 @@ const struct of_device_id dwc2_of_match_table[] = {
 	  .data = dwc2_set_amlogic_a1_params },
 	{ .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params },
 	{ .compatible = "apm,apm82181-dwc-otg", .data = dwc2_set_amcc_params },
+	{ .compatible = "sophgo,cv1800-usb",
+	  .data = dwc2_set_cv1800_params },
 	{ .compatible = "st,stm32f4x9-fsotg",
 	  .data = dwc2_set_stm32f4x9_fsotg_params },
 	{ .compatible = "st,stm32f4x9-hsotg" },
--
2.44.0


^ permalink raw reply related

* [PATCH 1/2] dt-bindings: usb: dwc2: Add support for Sophgo CV18XX/SG200X series SoC
From: Inochi Amaoto @ 2024-03-26  2:37 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Minas Harutyunyan, Paul Walmsley, Palmer Dabbelt,
	Albert Ou
  Cc: Chen Wang, Liu Gui, Inochi Amaoto, linux-usb, devicetree,
	linux-kernel, linux-riscv
In-Reply-To: <IA1PR20MB49537ED844CEBF19880326CEBB352@IA1PR20MB4953.namprd20.prod.outlook.com>

Add compatible string for the DWC2 IP which is used by
Sophgo CV18XX/SG2000 series SoC.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
---
 Documentation/devicetree/bindings/usb/dwc2.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/usb/dwc2.yaml b/Documentation/devicetree/bindings/usb/dwc2.yaml
index 0a5c98ea711d..9a2106e7b4b6 100644
--- a/Documentation/devicetree/bindings/usb/dwc2.yaml
+++ b/Documentation/devicetree/bindings/usb/dwc2.yaml
@@ -59,6 +59,7 @@ properties:
       - const: amcc,dwc-otg
       - const: apm,apm82181-dwc-otg
       - const: snps,dwc2
+      - const: sophgo,cv1800-usb
       - const: st,stm32f4x9-fsotg
       - const: st,stm32f4x9-hsotg
       - const: st,stm32f7-hsotg
--
2.44.0


^ permalink raw reply related

* [PATCH 0/2] riscv: sophgo: add support for usb controller of CV18XX/SG200X
From: Inochi Amaoto @ 2024-03-26  2:36 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Minas Harutyunyan, Paul Walmsley, Palmer Dabbelt,
	Albert Ou
  Cc: Chen Wang, Liu Gui, Inochi Amaoto, linux-usb, devicetree,
	linux-kernel, linux-riscv

Add usb controller params for the DWC2 USB ip in CV18XX/SG200X

Inochi Amaoto (2):
  dt-bindings: usb: dwc2: Add support for Sophgo CV18XX/SG200X series
    SoC
  usb: dwc2: add support for Sophgo CV18XX/SG200X series SoC

 .../devicetree/bindings/usb/dwc2.yaml         |  1 +
 drivers/usb/dwc2/params.c                     | 21 +++++++++++++++++++
 2 files changed, 22 insertions(+)

--
2.44.0


^ permalink raw reply

* Re: [PATCH] of: property: fw_devlink: Fix stupid bug in remote-endpoint parsing
From: John Watts @ 2024-03-26  2:31 UTC (permalink / raw)
  To: Saravana Kannan
  Cc: Rob Herring, Frank Rowand, Hervé Codina, Luca Ceresoli,
	kernel-team, Rob Herring, devicetree, linux-kernel
In-Reply-To: <CAGETcx-Emvu41nB3UDnb4Gh2aJEKu_hFcHX89uWnBTnaqvpN8g@mail.gmail.com>

Hello again,

On Mon, Mar 25, 2024 at 06:35:45PM -0700, Saravana Kannan wrote:
> Ok, I have a solution. Have the audio-graph-card2 find the fwnode of
> "multi" and mark it as "not a device" by doing something like this in
> the driver. That should help fw_devlink handle this correctly.
> 
> fwnode.flags |= FWNODE_FLAG_NOT_DEVICE;

I have done this:


	struct device_node *node = dev->of_node;
	struct device_node *node2;
	node2 = of_get_child_by_name(node, "multi");
	printk("node2 %pOF %pfw %x\n", node2, node2->fwnode, node2->fwnode.flags);
	node2->fwnode.flags |= FWNODE_FLAG_NOT_DEVICE;
	of_node_put(node2);

This doesn't do anything, but this does:

	struct device_node *node = dev->of_node;
	struct device_node *node2;
	node2 = of_get_child_by_name(node, "multi");
	fw_devlink_purge_absent_suppliers(&node2->fwnode);
	printk("node2 %pOF %pfw %x\n", node2, node2->fwnode, node2->fwnode.flags);
	of_node_put(node2);

Should I be using fw_devlink_purge_absent_suppliers?

> -Saravana

John.

^ permalink raw reply

* Re: [PATCH v6 09/15] media: bcm2835-unicam: Add support for CCP2/CSI2 camera interface
From: Laurent Pinchart @ 2024-03-26  1:50 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Dave Stevenson, David Plowman, Jean-Michel Hautbois,
	Hans Verkuil, Naushir Patuck, kernel-list, linux-rpi-kernel,
	Florian Fainelli, Ray Jui, Scott Branden,
	bcm-kernel-feedback-list, Conor Dooley, Krzysztof Kozlowski,
	Rob Herring, devicetree
In-Reply-To: <20240326013708.GA31396@pendragon.ideasonboard.com>

On Tue, Mar 26, 2024 at 03:37:09AM +0200, Laurent Pinchart wrote:
> Hi Sakari,
> 
> On Mon, Mar 25, 2024 at 06:36:49PM +0000, Sakari Ailus wrote:
> > On Fri, Mar 01, 2024 at 11:32:24PM +0200, Laurent Pinchart wrote:
> > > From: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > > 
> > > Add a 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>
> > > Co-developed-by: Naushir Patuck <naush@raspberrypi.com>
> > > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> > > Co-developed-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>
> > > Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>
> > > Co-developed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > 
> > Thanks for submitting this, it's the cleanest and neatest Unicom driver
> 
> Unicam, or if you insist Unicorn, but not Unicom :-)
> 
> > I've ever seen!
> > 
> > Some mostly unimportant comments below, however the bus-type issue needs to
> > be addressed.
> > 
> > > ---
> > > Changes since v5:
> > > 
> > > - Move to drivers/media/platform/broadcom/
> > > - Port to the upstream V4L2 streams API
> > > - Rebase on latest metadata API proposal
> > > - Add missing error message
> > > - Drop unneeded documentation block for unicam_isr()
> > > - Drop unneeded dev_dbg() and dev_err() messages
> > > - Drop unneeded streams_mask and fmt checks
> > > - Drop unused unicam_sd_pad_is_sink()
> > > - Drop unneeded includes
> > > - Drop v4l2_ctrl_subscribe_event() call
> > > - Use pm_runtime_resume_and_get()
> > > - Indentation and line wrap fixes
> > > - Let the framework set bus_info
> > > - Use v4l2_fwnode_endpoint_parse()
> > > - Fix media device cleanup
> > > - Drop lane reordering checks
> > > - Fix subdev state locking
> > > - Drop extra debug messages
> > > - Move clock handling to runtime PM handlers
> > > - Reorder functions
> > > - Rename init functions for more clarity
> > > - Initialize runtime PM earlier
> > > - Clarify error messages
> > > - Simplify subdev init with local variable
> > > - Fix subdev cleanup
> > > - Fix typos and indentation
> > > - Don't initialize local variables needlessly
> > > - Simplify num lanes check
> > > - Fix metadata handling in subdev set_fmt
> > > - Drop manual fallback to .s_stream()
> > > - Pass v4l2_pix_format to unicam_calc_format_size_bpl()
> > > - Simplify unicam_set_default_format()
> > > - Fix default format settings
> > > - Add busy check in unicam_s_fmt_meta()
> > > - Add missing \n at end of format strings
> > > - Fix metadata handling in subdev set_fmt
> > > - Fix locking when starting streaming
> > > - Return buffers from start streaming fails
> > > - Fix format validation for metadata node
> > > - Use video_device_pipeline_{start,stop}() helpers
> > > - Simplify format enumeration
> > > - Drop unset variable
> > > - Update MAINTAINERS entry
> > > - Update to the upstream v4l2_async_nf API
> > > - Update to the latest subdev routing API
> > > - Update to the latest subdev state API
> > > - Move from subdev .init_cfg() to .init_state()
> > > - Update to the latest videobuf2 API
> > > - Fix v4l2_subdev_enable_streams() error check
> > > - Use correct pad for the connected subdev
> > > - Return buffers to vb2 when start streaming fails
> > > - Improve debugging in start streaming handler
> > > - Simplify DMA address management
> > > - Drop comment about bcm2835-camera driver
> > > - Clarify comments that explain min/max sizes
> > > - Pass v4l2_pix_format to unicam_try_fmt()
> > > - Drop unneeded local variables
> > > - Rename image-related constants and functions
> > > - Turn unicam_fmt.metadata_fmt into bool
> > > - Rename unicam_fmt to unicam_format_info
> > > - Rename unicam_format_info variables to fmtinfo
> > > - Rename unicam_node.v_fmt to fmt
> > > - Add metadata formats for RAW10, RAW12 and RAW14
> > > - Make metadata formats line-based
> > > - Validate format on metadata video device
> > > - Add Co-devlopped-by tags
> > > 
> > > Changes since v3:
> > > 
> > > - Add the vendor prefix for DT name
> > > - Use the reg-names in DT parsing
> > > - Remove MAINTAINERS entry
> > > 
> > > Changes since v2:
> > > 
> > > - Change code organization
> > > - Remove unused variables
> > > - Correct the fmt_meta functions
> > > - Rewrite the start/stop streaming
> > >   - You can now start the image node alone, but not the metadata one
> > >   - The buffers are allocated per-node
> > >   - only the required stream is started, if the route exists and is
> > >     enabled
> > > - Prefix the macros with UNICAM_ to not have too generic names
> > > - Drop colorspace support
> > > 
> > > Changes since v1:
> > > 
> > > - Replace the unicam_{info,debug,error} macros with dev_*()
> > > ---
> > >  MAINTAINERS                                   |    1 +
> > >  drivers/media/platform/Kconfig                |    1 +
> > >  drivers/media/platform/Makefile               |    1 +
> > >  drivers/media/platform/broadcom/Kconfig       |   23 +
> > >  drivers/media/platform/broadcom/Makefile      |    3 +
> > >  .../platform/broadcom/bcm2835-unicam-regs.h   |  255 ++
> > >  .../media/platform/broadcom/bcm2835-unicam.c  | 2607 +++++++++++++++++
> > >  7 files changed, 2891 insertions(+)
> > >  create mode 100644 drivers/media/platform/broadcom/Kconfig
> > >  create mode 100644 drivers/media/platform/broadcom/Makefile
> > >  create mode 100644 drivers/media/platform/broadcom/bcm2835-unicam-regs.h
> > >  create mode 100644 drivers/media/platform/broadcom/bcm2835-unicam.c
> > > 
> > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > index e50a59654e6e..cc350729f467 100644
> > > --- a/MAINTAINERS
> > > +++ b/MAINTAINERS
> > > @@ -4002,6 +4002,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 91e54215de3a..2d79bfc68c15 100644
> > > --- a/drivers/media/platform/Kconfig
> > > +++ b/drivers/media/platform/Kconfig
> > > @@ -67,6 +67,7 @@ source "drivers/media/platform/amlogic/Kconfig"
> > >  source "drivers/media/platform/amphion/Kconfig"
> > >  source "drivers/media/platform/aspeed/Kconfig"
> > >  source "drivers/media/platform/atmel/Kconfig"
> > > +source "drivers/media/platform/broadcom/Kconfig"
> > >  source "drivers/media/platform/cadence/Kconfig"
> > >  source "drivers/media/platform/chips-media/Kconfig"
> > >  source "drivers/media/platform/intel/Kconfig"
> > > diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
> > > index 3296ec1ebe16..da17301f7439 100644
> > > --- a/drivers/media/platform/Makefile
> > > +++ b/drivers/media/platform/Makefile
> > > @@ -10,6 +10,7 @@ obj-y += amlogic/
> > >  obj-y += amphion/
> > >  obj-y += aspeed/
> > >  obj-y += atmel/
> > > +obj-y += broadcom/
> > >  obj-y += cadence/
> > >  obj-y += chips-media/
> > >  obj-y += intel/
> > > diff --git a/drivers/media/platform/broadcom/Kconfig b/drivers/media/platform/broadcom/Kconfig
> > > new file mode 100644
> > > index 000000000000..cc2c9afcc948
> > > --- /dev/null
> > > +++ b/drivers/media/platform/broadcom/Kconfig
> > > @@ -0,0 +1,23 @@
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +
> > > +config VIDEO_BCM2835_UNICAM
> > > +	tristate "Broadcom BCM283x/BCM271x Unicam video capture driver"
> > > +	depends on ARCH_BCM2835 || COMPILE_TEST
> > > +	depends on PM
> > > +	depends on VIDEO_DEV
> > > +	select MEDIA_CONTROLLER
> > > +	select V4L2_FWNODE
> > > +	select VIDEO_V4L2_SUBDEV_API
> > > +	select VIDEOBUF2_DMA_CONTIG
> > > +	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.
> > > +
> > > +	  To compile this driver as a module, choose M here. The module will be
> > > +	  called bcm2835-unicam.
> > > diff --git a/drivers/media/platform/broadcom/Makefile b/drivers/media/platform/broadcom/Makefile
> > > new file mode 100644
> > > index 000000000000..03d2045aba2e
> > > --- /dev/null
> > > +++ b/drivers/media/platform/broadcom/Makefile
> > > @@ -0,0 +1,3 @@
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +
> > > +obj-$(CONFIG_VIDEO_BCM2835_UNICAM) += bcm2835-unicam.o
> > > diff --git a/drivers/media/platform/broadcom/bcm2835-unicam-regs.h b/drivers/media/platform/broadcom/bcm2835-unicam-regs.h
> > > new file mode 100644
> > > index 000000000000..84775fd2fac5
> > > --- /dev/null
> > > +++ b/drivers/media/platform/broadcom/bcm2835-unicam-regs.h
> > > @@ -0,0 +1,255 @@
> > > +/* SPDX-License-Identifier: GPL-2.0-only */
> > > +
> > > +/*
> > > + * Copyright (C) 2017-2020 Raspberry Pi Trading.
> > 
> > Anything up to 2024?
> 
> Not really. The registers haven't really changed :-) I'll update the
> copyright in the .c file though.
> 
> > > + * Dave Stevenson <dave.stevenson@raspberrypi.com>
> > > + */
> 
> [snip]
> 
> > > diff --git a/drivers/media/platform/broadcom/bcm2835-unicam.c b/drivers/media/platform/broadcom/bcm2835-unicam.c
> > > new file mode 100644
> > > index 000000000000..716c89b8a217
> > > --- /dev/null
> > > +++ b/drivers/media/platform/broadcom/bcm2835-unicam.c
> > > @@ -0,0 +1,2607 @@
> 
> [snip]
> 
> > > +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 = unicam_reg_read(unicam, UNICAM_STA);
> > > +	/* Write value back to clear the interrupts */
> > > +	unicam_reg_write(unicam, UNICAM_STA, sta);
> > > +
> > > +	ista = unicam_reg_read(unicam, UNICAM_ISTA);
> > > +	/* Write value back to clear the interrupts */
> > > +	unicam_reg_write(unicam, UNICAM_ISTA, ista);
> > > +
> > > +	dev_dbg(unicam->dev, "ISR: ISTA: 0x%X, STA: 0x%X, sequence %d, lines done %d\n",
> > > +		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;
> > > +
> > > +	/*
> > > +	 * 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++;
> > 
> > Does access to this data need to be serialised somehow.
> 
> Given that it's only accessed from the interrupt handler (beside
> start_streaming time, before starting the hardware), I don't think so.
> 
> > > +	}
> > > +
> > > +	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 (unicam_reg_read(unicam, UNICAM_ICTL) & UNICAM_FCM) {
> > > +		/* Switch out of trigger mode if selected */
> > > +		unicam_reg_write_field(unicam, UNICAM_ICTL, 1, UNICAM_TFC);
> > > +		unicam_reg_write_field(unicam, UNICAM_ICTL, 0, UNICAM_FCM);
> > > +	}
> > > +	return IRQ_HANDLED;
> > > +}
> > > +
> > > +static void unicam_set_packing_config(struct unicam_device *unicam)
> > > +{
> > > +	struct unicam_node *node = &unicam->node[UNICAM_IMAGE_NODE];
> > > +	u32 pack, unpack;
> > > +	u32 val;
> > > +
> > > +	if (node->fmt.fmt.pix.pixelformat == node->fmtinfo->fourcc) {
> > > +		unpack = UNICAM_PUM_NONE;
> > > +		pack = UNICAM_PPM_NONE;
> > > +	} else {
> > > +		switch (node->fmtinfo->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;
> > 
> > Also 8-bit data?
> 
> Not that I know of. The 8-bit entries in unicam_image_formats have no
> .unpacked_fourcc field, so the condition in the if above will always be
> true for those as they can only be selected by setting the pixel format
> to fmtinfo->fourcc.
> 
> > > +	}
> > > +
> > > +	val = 0;
> > 
> > You could do initialisation in declaration.
> 
> Yes, but I think it's more readable to keep all the code that affects
> the 'val' variable together.
> 
> > > +	unicam_set_field(&val, unpack, UNICAM_PUM_MASK);
> > > +	unicam_set_field(&val, pack, UNICAM_PPM_MASK);
> > > +	unicam_reg_write(unicam, UNICAM_IPIPE, val);
> > > +}
> > > +
> > > +static void unicam_cfg_image_id(struct unicam_device *unicam)
> > > +{
> > > +	struct unicam_node *node = &unicam->node[UNICAM_IMAGE_NODE];
> > > +
> > > +	if (unicam->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > > +		/* CSI2 mode, hardcode VC 0 for now. */
> > > +		unicam_reg_write(unicam, UNICAM_IDI0,
> > > +				 (0 << 6) | node->fmtinfo->csi_dt);
> > > +	} else {
> > > +		/* CCP2 mode */
> > > +		unicam_reg_write(unicam, UNICAM_IDI0,
> > > +				 0x80 | node->fmtinfo->csi_dt);
> > > +	}
> > > +}
> > > +
> > > +static void unicam_enable_ed(struct unicam_device *unicam)
> > > +{
> > > +	u32 val = unicam_reg_read(unicam, UNICAM_DCS);
> > > +
> > > +	unicam_set_field(&val, 2, UNICAM_EDL_MASK);
> > > +	/* Do not wrap at the end of the embedded data buffer */
> > > +	unicam_set_field(&val, 0, UNICAM_DBOB);
> > > +
> > > +	unicam_reg_write(unicam, UNICAM_DCS, val);
> > > +}
> > > +
> > > +static void unicam_start_rx(struct unicam_device *unicam,
> > > +			    struct unicam_buffer *buf)
> > > +{
> > > +	struct unicam_node *node = &unicam->node[UNICAM_IMAGE_NODE];
> > > +	int line_int_freq = node->fmt.fmt.pix.height >> 2;
> > > +	unsigned int i;
> > > +	u32 val;
> > > +
> > > +	if (line_int_freq < 128)
> > > +		line_int_freq = 128;
> > 
> > 	line_int_freq = max(line_int_freq, 128);
> Ack.
> 
> > > +
> > > +	/* Enable lane clocks */
> > > +	val = 1;
> > 
> > Initialise in the loop initialisation below, I'd say.
> 
> How about
> 
> 	val = 0x55 & GENMASK(unicam->pipe.num_data_lanes * 2 - 1, 0);

I meant

 	val = 0x155 & GENMASK(unicam->pipe.num_data_lanes * 2 + 1, 0);

Maybe a comment would be useful ?

	/*
	 * Enable lane clocks. The register is structured as follows:
	 *
	 * [9:8] - DAT3
	 * [7:6] - DAT2
	 * [5:4] - DAT1
	 * [3:2] - DAT0
	 * [1:0] - CLK
	 *
	 * Enabled lane must be set to b01, and disabled lanes to b00. The clock
	 * lane is always enabled.
	 */
	val = 0x155 & GENMASK(unicam->pipe.num_data_lanes * 2 + 1, 0);

> > > +	for (i = 0; i < unicam->active_data_lanes; i++)
> > > +		val = val << 2 | 1;
> > > +	unicam_clk_write(unicam, val);
> > > +
> > > +	/* Basic init */
> > > +	unicam_reg_write(unicam, UNICAM_CTRL, UNICAM_MEM);
> > > +
> > > +	/* Enable analogue control, and leave in reset. */
> > > +	val = UNICAM_AR;
> > > +	unicam_set_field(&val, 7, UNICAM_CTATADJ_MASK);
> > > +	unicam_set_field(&val, 7, UNICAM_PTATADJ_MASK);
> > > +	unicam_reg_write(unicam, UNICAM_ANA, val);
> > > +	usleep_range(1000, 2000);
> > > +
> > > +	/* Come out of reset */
> > > +	unicam_reg_write_field(unicam, UNICAM_ANA, 0, UNICAM_AR);
> > > +
> > > +	/* Peripheral reset */
> > > +	unicam_reg_write_field(unicam, UNICAM_CTRL, 1, UNICAM_CPR);
> > > +	unicam_reg_write_field(unicam, UNICAM_CTRL, 0, UNICAM_CPR);
> > > +
> > > +	unicam_reg_write_field(unicam, UNICAM_CTRL, 0, UNICAM_CPE);
> > > +
> > > +	/* Enable Rx control. */
> > > +	val = unicam_reg_read(unicam, UNICAM_CTRL);
> > > +	if (unicam->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > > +		unicam_set_field(&val, UNICAM_CPM_CSI2, UNICAM_CPM_MASK);
> > > +		unicam_set_field(&val, UNICAM_DCM_STROBE, UNICAM_DCM_MASK);
> > > +	} else {
> > > +		unicam_set_field(&val, UNICAM_CPM_CCP2, UNICAM_CPM_MASK);
> > > +		unicam_set_field(&val, unicam->bus_flags, UNICAM_DCM_MASK);
> > > +	}
> > > +	/* Packet framer timeout */
> > > +	unicam_set_field(&val, 0xf, UNICAM_PFT_MASK);
> > > +	unicam_set_field(&val, 128, UNICAM_OET_MASK);
> > > +	unicam_reg_write(unicam, UNICAM_CTRL, val);
> > > +
> > > +	unicam_reg_write(unicam, UNICAM_IHWIN, 0);
> > > +	unicam_reg_write(unicam, UNICAM_IVWIN, 0);
> > > +
> > > +	/* AXI bus access QoS setup */
> > > +	val = unicam_reg_read(unicam, UNICAM_PRI);
> > > +	unicam_set_field(&val, 0, UNICAM_BL_MASK);
> > > +	unicam_set_field(&val, 0, UNICAM_BS_MASK);
> > > +	unicam_set_field(&val, 0xe, UNICAM_PP_MASK);
> > > +	unicam_set_field(&val, 8, UNICAM_NP_MASK);
> > > +	unicam_set_field(&val, 2, UNICAM_PT_MASK);
> > > +	unicam_set_field(&val, 1, UNICAM_PE);
> > > +	unicam_reg_write(unicam, UNICAM_PRI, val);
> > > +
> > > +	unicam_reg_write_field(unicam, UNICAM_ANA, 0, UNICAM_DDL);
> > > +
> > > +	/* Always start in trigger frame capture mode (UNICAM_FCM set) */
> > > +	val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM | UNICAM_IBOB;
> > > +	unicam_set_field(&val, line_int_freq, UNICAM_LCIE_MASK);
> > > +	unicam_reg_write(unicam, UNICAM_ICTL, val);
> > > +	unicam_reg_write(unicam, UNICAM_STA, UNICAM_STA_MASK_ALL);
> > > +	unicam_reg_write(unicam, UNICAM_ISTA, UNICAM_ISTA_MASK_ALL);
> > > +
> > > +	/* tclk_term_en */
> > > +	unicam_reg_write_field(unicam, UNICAM_CLT, 2, UNICAM_CLT1_MASK);
> > > +	/* tclk_settle */
> > > +	unicam_reg_write_field(unicam, UNICAM_CLT, 6, UNICAM_CLT2_MASK);
> > > +	/* td_term_en */
> > > +	unicam_reg_write_field(unicam, UNICAM_DLT, 2, UNICAM_DLT1_MASK);
> > > +	/* ths_settle */
> > > +	unicam_reg_write_field(unicam, UNICAM_DLT, 6, UNICAM_DLT2_MASK);
> > > +	/* trx_enable */
> > > +	unicam_reg_write_field(unicam, UNICAM_DLT, 0, UNICAM_DLT3_MASK);
> > > +
> > > +	unicam_reg_write_field(unicam, UNICAM_CTRL, 0, UNICAM_SOE);
> > > +
> > > +	/* Packet compare setup - required to avoid missing frame ends */
> > > +	val = 0;
> > > +	unicam_set_field(&val, 1, UNICAM_PCE);
> > > +	unicam_set_field(&val, 1, UNICAM_GI);
> > > +	unicam_set_field(&val, 1, UNICAM_CPH);
> > > +	unicam_set_field(&val, 0, UNICAM_PCVC_MASK);
> > > +	unicam_set_field(&val, 1, UNICAM_PCDT_MASK);
> > > +	unicam_reg_write(unicam, UNICAM_CMP0, val);
> > > +
> > > +	/* Enable clock lane and set up terminations */
> > > +	val = 0;
> > > +	if (unicam->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > > +		/* CSI2 */
> > > +		unicam_set_field(&val, 1, UNICAM_CLE);
> > > +		unicam_set_field(&val, 1, UNICAM_CLLPE);
> > > +		if (!(unicam->bus_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)) {
> > > +			unicam_set_field(&val, 1, UNICAM_CLTRE);
> > > +			unicam_set_field(&val, 1, UNICAM_CLHSE);
> > > +		}
> > > +	} else {
> > > +		/* CCP2 */
> > > +		unicam_set_field(&val, 1, UNICAM_CLE);
> > > +		unicam_set_field(&val, 1, UNICAM_CLHSE);
> > > +		unicam_set_field(&val, 1, UNICAM_CLTRE);
> > > +	}
> > > +	unicam_reg_write(unicam, 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 (unicam->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > > +		/* CSI2 */
> > > +		unicam_set_field(&val, 1, UNICAM_DLE);
> > > +		unicam_set_field(&val, 1, UNICAM_DLLPE);
> > > +		if (!(unicam->bus_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)) {
> > > +			unicam_set_field(&val, 1, UNICAM_DLTRE);
> > > +			unicam_set_field(&val, 1, UNICAM_DLHSE);
> > > +		}
> > > +	} else {
> > > +		/* CCP2 */
> > > +		unicam_set_field(&val, 1, UNICAM_DLE);
> > > +		unicam_set_field(&val, 1, UNICAM_DLHSE);
> > > +		unicam_set_field(&val, 1, UNICAM_DLTRE);
> > > +	}
> > > +	unicam_reg_write(unicam, UNICAM_DAT0, val);
> > > +
> > > +	if (unicam->active_data_lanes == 1)
> > > +		val = 0;
> > > +	unicam_reg_write(unicam, UNICAM_DAT1, val);
> > > +
> > > +	if (unicam->max_data_lanes > 2) {
> > > +		/*
> > > +		 * Registers UNICAM_DAT2 and UNICAM_DAT3 only valid if the
> > > +		 * instance supports more than 2 data lanes.
> > > +		 */
> > > +		if (unicam->active_data_lanes == 2)
> > > +			val = 0;
> > > +		unicam_reg_write(unicam, UNICAM_DAT2, val);
> > > +
> > > +		if (unicam->active_data_lanes == 3)
> > > +			val = 0;
> > > +		unicam_reg_write(unicam, UNICAM_DAT3, val);
> > > +	}
> > > +
> > > +	unicam_reg_write(unicam, UNICAM_IBLS,
> > > +			 node->fmt.fmt.pix.bytesperline);
> > > +	unicam_wr_dma_addr(&unicam->node[UNICAM_IMAGE_NODE], buf);
> > > +	unicam_set_packing_config(unicam);
> > > +	unicam_cfg_image_id(unicam);
> > > +
> > > +	val = unicam_reg_read(unicam, UNICAM_MISC);
> > > +	unicam_set_field(&val, 1, UNICAM_FL0);
> > > +	unicam_set_field(&val, 1, UNICAM_FL1);
> > > +	unicam_reg_write(unicam, UNICAM_MISC, val);
> > > +
> > > +	/* Enable peripheral */
> > > +	unicam_reg_write_field(unicam, UNICAM_CTRL, 1, UNICAM_CPE);
> > > +
> > > +	/* Load image pointers */
> > > +	unicam_reg_write_field(unicam, UNICAM_ICTL, 1, UNICAM_LIP_MASK);
> > > +
> > > +	/*
> > > +	 * Enable trigger only for the first frame to
> > > +	 * sync correctly to the FS from the source.
> > > +	 */
> > > +	unicam_reg_write_field(unicam, UNICAM_ICTL, 1, UNICAM_TFC);
> > > +}
> 
> [snip]
> 
> > > +static int unicam_async_nf_init(struct unicam_device *unicam)
> > > +{
> > > +	struct v4l2_fwnode_endpoint ep = { };
> > 
> > If the bus-type property is mandatory and you have no stated defaults
> > anywhere, this is fine. I.e. all the relevant properties would need to be
> > mandatory.
> 
> They are, as far as I can tell (well, the clock-noncontinuous property
> is not mandatory, but that's expected as it's a flag).
> 
> > > +	struct fwnode_handle *ep_handle;
> > > +	struct v4l2_async_connection *asc;
> > > +	int ret;
> > > +
> > > +	ret = of_property_read_u32(unicam->dev->of_node, "brcm,num-data-lanes",
> > > +				   &unicam->max_data_lanes);
> > > +	if (ret < 0) {
> > > +		dev_err(unicam->dev, "Missing %s DT property\n",
> > > +			"brcm,num-data-lanes");
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	/* Get and parse the local endpoint. */
> > > +	ep_handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(unicam->dev), 0, 0,
> > > +						    FWNODE_GRAPH_ENDPOINT_NEXT);
> > > +	if (!ep_handle) {
> > > +		dev_err(unicam->dev, "No endpoint found\n");
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	ret = v4l2_fwnode_endpoint_parse(ep_handle, &ep);
> > > +	if (ret) {
> > > +		dev_err(unicam->dev, "Failed to parse endpoint: %d\n", ret);
> > > +		goto error;
> > > +	}
> > > +
> > > +	unicam->bus_type = ep.bus_type;
> > > +
> > > +	switch (ep.bus_type) {
> > > +	case V4L2_MBUS_CSI2_DPHY: {
> > > +		unsigned int num_data_lanes = ep.bus.mipi_csi2.num_data_lanes;
> > > +
> > > +		if (num_data_lanes != 1 && num_data_lanes != 2 &&
> > > +		    num_data_lanes != 4) {
> > > +			dev_err(unicam->dev, "%u data lanes not supported\n",
> > > +				num_data_lanes);
> > > +			goto error;
> > > +		}
> > > +
> > > +		if (num_data_lanes > unicam->max_data_lanes) {
> > > +			dev_err(unicam->dev,
> > > +				"Endpoint uses %u data lanes when %u are supported\n",
> > > +				num_data_lanes, unicam->max_data_lanes);
> > > +			goto error;
> > > +		}
> > > +
> > > +		unicam->active_data_lanes = num_data_lanes;
> > > +		unicam->bus_flags = ep.bus.mipi_csi2.flags;
> > > +		break;
> > > +	}
> > > +
> > > +	case V4L2_MBUS_CCP2:
> > > +		unicam->max_data_lanes = 1;
> > > +		unicam->active_data_lanes = 1;
> > > +		unicam->bus_flags = ep.bus.mipi_csi1.strobe;
> > > +		break;
> > > +
> > > +	default:
> > > +		/* Unsupported bus type */
> > > +		dev_err(unicam->dev, "Unsupported bus type %u\n", ep.bus_type);
> > > +		goto error;
> > > +	}
> > > +
> > > +	/* Initialize and register the async notifier. */
> > > +	v4l2_async_nf_init(&unicam->notifier, &unicam->v4l2_dev);
> > > +
> > > +	asc = v4l2_async_nf_add_fwnode_remote(&unicam->notifier, ep_handle,
> > > +					      struct v4l2_async_connection);
> > > +	fwnode_handle_put(ep_handle);
> > > +	ep_handle = NULL;
> > > +
> > > +	if (IS_ERR(asc)) {
> > > +		ret = PTR_ERR(asc);
> > > +		dev_err(unicam->dev, "Failed to add entry to notifier: %d\n",
> > > +			ret);
> > > +		goto error;
> > > +	}
> > > +
> > > +	unicam->notifier.ops = &unicam_async_ops;
> > > +
> > > +	ret = v4l2_async_nf_register(&unicam->notifier);
> > > +	if (ret) {
> > > +		dev_err(unicam->dev, "Error registering device notifier: %d\n",
> > > +			ret);
> > > +		goto error;
> > > +	}
> > > +
> > > +	return 0;
> > > +
> > > +error:
> > > +	fwnode_handle_put(ep_handle);
> > > +	return ret;
> > > +}
> > > +
> > > +/* -----------------------------------------------------------------------------
> > > + * Probe & remove
> > > + */
> > > +
> > > +static int unicam_media_init(struct unicam_device *unicam)
> > > +{
> > > +	int ret;
> > > +
> > > +	unicam->mdev.dev = unicam->dev;
> > > +	strscpy(unicam->mdev.model, UNICAM_MODULE_NAME,
> > > +		sizeof(unicam->mdev.model));
> > > +	strscpy(unicam->mdev.serial, "", sizeof(unicam->mdev.serial));
> > 
> > Isn't the field already zeroed?
> 
> Indeed. I'll drop this.
> 
> > 
> > > +	unicam->mdev.hw_revision = 0;
> > > +
> > > +	media_device_init(&unicam->mdev);
> > > +
> > > +	unicam->v4l2_dev.mdev = &unicam->mdev;
> > > +
> > > +	ret = v4l2_device_register(unicam->dev, &unicam->v4l2_dev);
> > > +	if (ret < 0) {
> > > +		dev_err(unicam->dev, "Unable to register v4l2 device\n");
> > > +		goto err_media_cleanup;
> > > +	}
> > > +
> > > +	ret = media_device_register(&unicam->mdev);
> > > +	if (ret < 0) {
> > > +		dev_err(unicam->dev,
> > > +			"Unable to register media-controller device\n");
> > > +		goto err_v4l2_unregister;
> > > +	}
> > > +
> > > +	return 0;
> > > +
> > > +err_v4l2_unregister:
> > > +	v4l2_device_unregister(&unicam->v4l2_dev);
> > > +err_media_cleanup:
> > > +	media_device_cleanup(&unicam->mdev);
> > > +	return ret;
> > > +}
> 
> [snip]

-- 
Regards,

Laurent Pinchart

^ permalink raw reply

* [PATCH v5 3/3] dmaengine: add driver for Sophgo CV18XX/SG200X dmamux
From: Inochi Amaoto @ 2024-03-26  1:47 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Chen Wang, Inochi Amaoto, Paul Walmsley, Palmer Dabbelt,
	Albert Ou
  Cc: Jisheng Zhang, Liu Gui, Jingbao Qiu, dlan, dmaengine, devicetree,
	linux-kernel, linux-riscv
In-Reply-To: <IA1PR20MB4953B500D7451964EE37DA4CBB352@IA1PR20MB4953.namprd20.prod.outlook.com>

Sophgo CV18XX/SG200X use DW AXI CORE with a multiplexer for remapping
its request lines. The multiplexer supports at most 8 request lines.

Add driver for Sophgo CV18XX/SG200X DMA multiplexer.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
---
 drivers/dma/Kconfig         |   9 ++
 drivers/dma/Makefile        |   1 +
 drivers/dma/cv1800-dmamux.c | 268 ++++++++++++++++++++++++++++++++++++
 3 files changed, 278 insertions(+)
 create mode 100644 drivers/dma/cv1800-dmamux.c

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 002a5ec80620..cb31520b9f86 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -546,6 +546,15 @@ config PLX_DMA
 	  These are exposed via extra functions on the switch's
 	  upstream port. Each function exposes one DMA channel.

+config SOPHGO_CV1800_DMAMUX
+	tristate "Sophgo CV1800/SG2000 series SoC DMA multiplexer support"
+	depends on MFD_SYSCON
+	depends on ARCH_SOPHGO
+	help
+	  Support for the DMA multiplexer on Sophgo CV1800/SG2000
+	  series SoCs.
+	  Say Y here if your board have this soc.
+
 config STE_DMA40
 	bool "ST-Ericsson DMA40 support"
 	depends on ARCH_U8500
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index dfd40d14e408..7465f249ee47 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
 obj-$(CONFIG_PXA_DMA) += pxa_dma.o
 obj-$(CONFIG_RENESAS_DMA) += sh/
 obj-$(CONFIG_SF_PDMA) += sf-pdma/
+obj-$(CONFIG_SOPHGO_CV1800_DMAMUX) += cv1800-dmamux.o
 obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
 obj-$(CONFIG_STM32_DMA) += stm32-dma.o
 obj-$(CONFIG_STM32_DMAMUX) += stm32-dmamux.o
diff --git a/drivers/dma/cv1800-dmamux.c b/drivers/dma/cv1800-dmamux.c
new file mode 100644
index 000000000000..9c01f157ab97
--- /dev/null
+++ b/drivers/dma/cv1800-dmamux.c
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/of_dma.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/llist.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+#include <linux/mfd/syscon.h>
+
+#include <soc/sophgo/cv1800-sysctl.h>
+#include <dt-bindings/dma/cv1800-dma.h>
+
+#define DMAMUX_NCELLS			2
+#define MAX_DMA_MAPPING_ID		DMA_SPI_NOR1
+#define MAX_DMA_CPU_ID			DMA_CPU_C906_1
+#define MAX_DMA_CH_ID			7
+
+#define DMAMUX_INTMUX_REGISTER_LEN	4
+#define DMAMUX_NR_CH_PER_REGISTER	4
+#define DMAMUX_BIT_PER_CH		8
+#define DMAMUX_CH_MASk			GENMASK(5, 0)
+#define DMAMUX_INT_BIT_PER_CPU		10
+#define DMAMUX_CH_UPDATE_BIT		BIT(31)
+
+#define DMAMUX_CH_REGPOS(chid) \
+	((chid) / DMAMUX_NR_CH_PER_REGISTER)
+#define DMAMUX_CH_REGOFF(chid) \
+	((chid) % DMAMUX_NR_CH_PER_REGISTER)
+#define DMAMUX_CH_REG(chid) \
+	((DMAMUX_CH_REGPOS(chid) * sizeof(u32)) + \
+	 CV1800_SDMA_DMA_CHANNEL_REMAP0)
+#define DMAMUX_CH_SET(chid, val) \
+	(((val) << (DMAMUX_CH_REGOFF(chid) * DMAMUX_BIT_PER_CH)) | \
+	 DMAMUX_CH_UPDATE_BIT)
+#define DMAMUX_CH_MASK(chid) \
+	DMAMUX_CH_SET(chid, DMAMUX_CH_MASk)
+
+#define DMAMUX_INT_BIT(chid, cpuid) \
+	BIT((cpuid) * DMAMUX_INT_BIT_PER_CPU + (chid))
+#define DMAMUX_INTEN_BIT(cpuid) \
+	DMAMUX_INT_BIT(8, cpuid)
+#define DMAMUX_INT_CH_BIT(chid, cpuid) \
+	(DMAMUX_INT_BIT(chid, cpuid) | DMAMUX_INTEN_BIT(cpuid))
+#define DMAMUX_INT_MASK(chid) \
+	(DMAMUX_INT_BIT(chid, DMA_CPU_A53) | \
+	 DMAMUX_INT_BIT(chid, DMA_CPU_C906_0) | \
+	 DMAMUX_INT_BIT(chid, DMA_CPU_C906_1))
+#define DMAMUX_INT_CH_MASK(chid, cpuid) \
+	(DMAMUX_INT_MASK(chid) | DMAMUX_INTEN_BIT(cpuid))
+
+struct cv1800_dmamux_data {
+	struct dma_router	dmarouter;
+	struct regmap		*regmap;
+	spinlock_t		lock;
+	struct llist_head	free_maps;
+	struct llist_head	reserve_maps;
+	DECLARE_BITMAP(mapped_peripherals, MAX_DMA_MAPPING_ID);
+};
+
+struct cv1800_dmamux_map {
+	struct llist_node node;
+	unsigned int channel;
+	unsigned int peripheral;
+	unsigned int cpu;
+};
+
+static void cv1800_dmamux_free(struct device *dev, void *route_data)
+{
+	struct cv1800_dmamux_data *dmamux = dev_get_drvdata(dev);
+	struct cv1800_dmamux_map *map = route_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dmamux->lock, flags);
+
+	regmap_update_bits(dmamux->regmap,
+			   DMAMUX_CH_REG(map->channel),
+			   DMAMUX_CH_MASK(map->channel),
+			   DMAMUX_CH_UPDATE_BIT);
+
+	regmap_update_bits(dmamux->regmap, CV1800_SDMA_DMA_INT_MUX,
+			   DMAMUX_INT_CH_MASK(map->channel, map->cpu),
+			   DMAMUX_INTEN_BIT(map->cpu));
+
+	spin_unlock_irqrestore(&dmamux->lock, flags);
+
+	dev_info(dev, "free channel %u for req %u (cpu %u)\n",
+		 map->channel, map->peripheral, map->cpu);
+}
+
+static void *cv1800_dmamux_route_allocate(struct of_phandle_args *dma_spec,
+					  struct of_dma *ofdma)
+{
+	struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
+	struct cv1800_dmamux_data *dmamux = platform_get_drvdata(pdev);
+	struct cv1800_dmamux_map *map;
+	struct llist_node *node;
+	unsigned long flags;
+	unsigned int chid, devid, cpuid;
+	int ret;
+
+	if (dma_spec->args_count != DMAMUX_NCELLS) {
+		dev_err(&pdev->dev, "invalid number of dma mux args\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	devid = dma_spec->args[0];
+	cpuid = dma_spec->args[1];
+	dma_spec->args_count = 1;
+
+	if (devid > MAX_DMA_MAPPING_ID) {
+		dev_err(&pdev->dev, "invalid device id: %u\n", devid);
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (cpuid > MAX_DMA_CPU_ID) {
+		dev_err(&pdev->dev, "invalid cpu id: %u\n", cpuid);
+		return ERR_PTR(-EINVAL);
+	}
+
+	dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
+	if (!dma_spec->np) {
+		dev_err(&pdev->dev, "can't get dma master\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	spin_lock_irqsave(&dmamux->lock, flags);
+
+	if (test_bit(devid, dmamux->mapped_peripherals)) {
+		llist_for_each_entry(map, dmamux->reserve_maps.first, node) {
+			if (map->peripheral == devid && map->cpu == cpuid)
+				goto found;
+		}
+
+		ret = -EINVAL;
+		goto failed;
+	} else {
+		node = llist_del_first(&dmamux->free_maps);
+		if (!node) {
+			ret = -ENODEV;
+			goto failed;
+		}
+
+		map = llist_entry(node, struct cv1800_dmamux_map, node);
+		llist_add(&map->node, &dmamux->reserve_maps);
+		set_bit(devid, dmamux->mapped_peripherals);
+	}
+
+found:
+	chid = map->channel;
+	map->peripheral = devid;
+	map->cpu = cpuid;
+
+	regmap_set_bits(dmamux->regmap,
+			DMAMUX_CH_REG(chid),
+			DMAMUX_CH_SET(chid, devid));
+
+	regmap_update_bits(dmamux->regmap, CV1800_SDMA_DMA_INT_MUX,
+			   DMAMUX_INT_CH_MASK(chid, cpuid),
+			   DMAMUX_INT_CH_BIT(chid, cpuid));
+
+	spin_unlock_irqrestore(&dmamux->lock, flags);
+
+	dma_spec->args[0] = chid;
+
+	dev_info(&pdev->dev, "register channel %u for req %u (cpu %u)\n",
+		 chid, devid, cpuid);
+
+	return map;
+
+failed:
+	spin_unlock_irqrestore(&dmamux->lock, flags);
+	of_node_put(dma_spec->np);
+	dev_err(&pdev->dev, "errno %d\n", ret);
+	return ERR_PTR(ret);
+
+}
+
+static int cv1800_dmamux_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *mux_node = dev->of_node;
+	struct cv1800_dmamux_data *data;
+	struct cv1800_dmamux_map *tmp;
+	struct device *parent = dev->parent;
+	struct device_node *dma_master;
+	struct regmap *regmap = NULL;
+	unsigned int i;
+
+	if (!parent)
+		return -ENODEV;
+
+	regmap = device_node_to_regmap(parent->of_node);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	dma_master = of_parse_phandle(mux_node, "dma-masters", 0);
+	if (!dma_master) {
+		dev_err(dev, "invalid dma-requests property\n");
+		return -ENODEV;
+	}
+	of_node_put(dma_master);
+
+	data = devm_kmalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	spin_lock_init(&data->lock);
+	init_llist_head(&data->free_maps);
+
+	for (i = 0; i <= MAX_DMA_CH_ID; i++) {
+		tmp = devm_kmalloc(dev, sizeof(*tmp), GFP_KERNEL);
+		if (!tmp) {
+			/* It is OK for not allocating all channel */
+			dev_warn(dev, "can not allocate channel %u\n", i);
+			continue;
+		}
+
+		init_llist_node(&tmp->node);
+		tmp->channel = i;
+		llist_add(&tmp->node, &data->free_maps);
+	}
+
+	/* if no channel is allocated, the probe must fail */
+	if (llist_empty(&data->free_maps))
+		return -ENOMEM;
+
+	data->regmap = regmap;
+	data->dmarouter.dev = dev;
+	data->dmarouter.route_free = cv1800_dmamux_free;
+
+	platform_set_drvdata(pdev, data);
+
+	return of_dma_router_register(mux_node,
+				      cv1800_dmamux_route_allocate,
+				      &data->dmarouter);
+}
+
+static void cv1800_dmamux_remove(struct platform_device *pdev)
+{
+	of_dma_controller_free(pdev->dev.of_node);
+}
+
+static const struct of_device_id cv1800_dmamux_ids[] = {
+	{ .compatible = "sophgo,cv1800-dmamux", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, cv1800_dmamux_ids);
+
+static struct platform_driver cv1800_dmamux_driver = {
+	.driver = {
+		.name = "cv1800-dmamux",
+		.of_match_table = cv1800_dmamux_ids,
+	},
+	.probe = cv1800_dmamux_probe,
+	.remove_new = cv1800_dmamux_remove,
+};
+module_platform_driver(cv1800_dmamux_driver);
+
+MODULE_AUTHOR("Inochi Amaoto <inochiama@outlook.com>");
+MODULE_DESCRIPTION("Sophgo CV1800/SG2000 Series Soc DMAMUX driver");
+MODULE_LICENSE("GPL");
--
2.44.0


^ permalink raw reply related

* [PATCH v5 2/3] soc/sophgo: add top sysctrl layout file for CV18XX/SG200X
From: Inochi Amaoto @ 2024-03-26  1:47 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Chen Wang, Inochi Amaoto, Paul Walmsley, Palmer Dabbelt,
	Albert Ou
  Cc: Jisheng Zhang, Liu Gui, Jingbao Qiu, dlan, dmaengine, devicetree,
	linux-kernel, linux-riscv
In-Reply-To: <IA1PR20MB4953B500D7451964EE37DA4CBB352@IA1PR20MB4953.namprd20.prod.outlook.com>

The "top" system controller of CV18XX/SG200X exposes control
register access for various devices. Add soc header file to
describe it.

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
---
 include/soc/sophgo/cv1800-sysctl.h | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 include/soc/sophgo/cv1800-sysctl.h

diff --git a/include/soc/sophgo/cv1800-sysctl.h b/include/soc/sophgo/cv1800-sysctl.h
new file mode 100644
index 000000000000..b9396d33e240
--- /dev/null
+++ b/include/soc/sophgo/cv1800-sysctl.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
+ */
+
+#ifndef CV1800_SYSCTL_H
+#define CV1800_SYSCTL_H
+
+/*
+ * SOPHGO CV1800/SG2000 SoC top system controller registers offsets.
+ */
+
+#define CV1800_CONF_INFO		0x004
+#define CV1800_SYS_CTRL_REG		0x008
+#define CV1800_USB_PHY_CTRL_REG		0x048
+#define CV1800_SDMA_DMA_CHANNEL_REMAP0	0x154
+#define CV1800_SDMA_DMA_CHANNEL_REMAP1	0x158
+#define CV1800_TOP_TIMER_CLK_SEL	0x1a0
+#define CV1800_TOP_WDT_CTRL		0x1a8
+#define CV1800_DDR_AXI_URGENT_OW	0x1b8
+#define CV1800_DDR_AXI_URGENT		0x1bc
+#define CV1800_DDR_AXI_QOS_0		0x1d8
+#define CV1800_DDR_AXI_QOS_1		0x1dc
+#define CV1800_SD_PWRSW_CTRL		0x1f4
+#define CV1800_SD_PWRSW_TIME		0x1f8
+#define CV1800_DDR_AXI_QOS_OW		0x23c
+#define CV1800_SD_CTRL_OPT		0x294
+#define CV1800_SDMA_DMA_INT_MUX		0x298
+
+#endif // CV1800_SYSCTL_H
--
2.44.0


^ permalink raw reply related

* [PATCH v5 1/3] dt-bindings: dmaengine: Add dmamux for CV18XX/SG200X series SoC
From: Inochi Amaoto @ 2024-03-26  1:47 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Chen Wang, Inochi Amaoto, Paul Walmsley, Palmer Dabbelt,
	Albert Ou
  Cc: Jisheng Zhang, Liu Gui, Jingbao Qiu, dlan, dmaengine, devicetree,
	linux-kernel, linux-riscv
In-Reply-To: <IA1PR20MB4953B500D7451964EE37DA4CBB352@IA1PR20MB4953.namprd20.prod.outlook.com>

The DMA IP of Sophgo CV18XX/SG200X is based on a DW AXI CORE, with
an additional channel remap register located in the top system control
area. The DMA channel is exclusive to each core.

Add the dmamux binding for CV18XX/SG200X series SoC

Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
---
 .../bindings/dma/sophgo,cv1800-dmamux.yaml    | 48 ++++++++++++++++
 include/dt-bindings/dma/cv1800-dma.h          | 55 +++++++++++++++++++
 2 files changed, 103 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
 create mode 100644 include/dt-bindings/dma/cv1800-dma.h

diff --git a/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml b/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
new file mode 100644
index 000000000000..d7256646ea26
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/dma/sophgo,cv1800-dmamux.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sophgo CV1800/SG200 Series DMA mux
+
+maintainers:
+  - Inochi Amaoto <inochiama@outlook.com>
+
+allOf:
+  - $ref: dma-router.yaml#
+
+properties:
+  compatible:
+    const: sophgo,cv1800-dmamux
+
+  reg:
+    items:
+      - description: DMA channal remapping register
+      - description: DMA channel interrupt mapping register
+
+  '#dma-cells':
+    const: 2
+    description:
+      The first cells is device id. The second one is the cpu id.
+
+  dma-masters:
+    maxItems: 1
+
+  dma-requests:
+    const: 8
+
+required:
+  - '#dma-cells'
+  - dma-masters
+
+additionalProperties: false
+
+examples:
+  - |
+    dma-router {
+      compatible = "sophgo,cv1800-dmamux";
+      #dma-cells = <2>;
+      dma-masters = <&dmac>;
+      dma-requests = <8>;
+    };
diff --git a/include/dt-bindings/dma/cv1800-dma.h b/include/dt-bindings/dma/cv1800-dma.h
new file mode 100644
index 000000000000..3ce9dac25259
--- /dev/null
+++ b/include/dt-bindings/dma/cv1800-dma.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+
+#ifndef __DT_BINDINGS_DMA_CV1800_H__
+#define __DT_BINDINGS_DMA_CV1800_H__
+
+#define DMA_I2S0_RX		0
+#define DMA_I2S0_TX		1
+#define DMA_I2S1_RX		2
+#define DMA_I2S1_TX		3
+#define DMA_I2S2_RX		4
+#define DMA_I2S2_TX		5
+#define DMA_I2S3_RX		6
+#define DMA_I2S3_TX		7
+#define DMA_UART0_RX		8
+#define DMA_UART0_TX		9
+#define DMA_UART1_RX		10
+#define DMA_UART1_TX		11
+#define DMA_UART2_RX		12
+#define DMA_UART2_TX		13
+#define DMA_UART3_RX		14
+#define DMA_UART3_TX		15
+#define DMA_SPI0_RX		16
+#define DMA_SPI0_TX		17
+#define DMA_SPI1_RX		18
+#define DMA_SPI1_TX		19
+#define DMA_SPI2_RX		20
+#define DMA_SPI2_TX		21
+#define DMA_SPI3_RX		22
+#define DMA_SPI3_TX		23
+#define DMA_I2C0_RX		24
+#define DMA_I2C0_TX		25
+#define DMA_I2C1_RX		26
+#define DMA_I2C1_TX		27
+#define DMA_I2C2_RX		28
+#define DMA_I2C2_TX		29
+#define DMA_I2C3_RX		30
+#define DMA_I2C3_TX		31
+#define DMA_I2C4_RX		32
+#define DMA_I2C4_TX		33
+#define DMA_TDM0_RX		34
+#define DMA_TDM0_TX		35
+#define DMA_TDM1_RX		36
+#define DMA_AUDSRC		37
+#define DMA_SPI_NAND		38
+#define DMA_SPI_NOR		39
+#define DMA_UART4_RX		40
+#define DMA_UART4_TX		41
+#define DMA_SPI_NOR1		42
+
+#define DMA_CPU_A53		0
+#define DMA_CPU_C906_0		1
+#define DMA_CPU_C906_1		2
+
+
+#endif // __DT_BINDINGS_DMA_CV1800_H__
--
2.44.0


^ permalink raw reply related

* [PATCH v5 0/3] riscv: sophgo: add dmamux support for Sophgo CV1800/SG2000 SoCs
From: Inochi Amaoto @ 2024-03-26  1:44 UTC (permalink / raw)
  To: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Chen Wang, Inochi Amaoto, Paul Walmsley, Palmer Dabbelt,
	Albert Ou
  Cc: Jisheng Zhang, Liu Gui, Jingbao Qiu, dlan, dmaengine, devicetree,
	linux-kernel, linux-riscv

Add dma multiplexer support for the Sophgo CV1800/SG2000 SoCs.

Changed from v4:
1. remove the syscon binding since it can not be complete (still
lack some subdevices)
2. add reg description for the binding,
3. remove the fixed channel assign for dmamux binding
3. driver adopt to the binding change. Now the driver allocates all the
channel when initing and maps the request chan to the channel dynamicly.

Changed from v3:
1. fix dt-binding address issue.

Changed from v2:
1. add reg property of dmamux node in the binding of patch 2

Changed from v1:
1. fix wrong title of patch 2.

Inochi Amaoto (3):
  dt-bindings: dmaengine: Add dmamux for CV18XX/SG200X series SoC
  soc/sophgo: add top sysctrl layout file for CV18XX/SG200X
  dmaengine: add driver for Sophgo CV18XX/SG200X dmamux

 .../bindings/dma/sophgo,cv1800-dmamux.yaml    |  48 ++++
 drivers/dma/Kconfig                           |   9 +
 drivers/dma/Makefile                          |   1 +
 drivers/dma/cv1800-dmamux.c                   | 268 ++++++++++++++++++
 include/dt-bindings/dma/cv1800-dma.h          |  55 ++++
 include/soc/sophgo/cv1800-sysctl.h            |  30 ++
 6 files changed, 411 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
 create mode 100644 drivers/dma/cv1800-dmamux.c
 create mode 100644 include/dt-bindings/dma/cv1800-dma.h
 create mode 100644 include/soc/sophgo/cv1800-sysctl.h

--
2.44.0


^ permalink raw reply

* Re: [PATCH] of: property: fw_devlink: Fix stupid bug in remote-endpoint parsing
From: John Watts @ 2024-03-26  1:42 UTC (permalink / raw)
  To: Saravana Kannan
  Cc: Rob Herring, Frank Rowand, Hervé Codina, Luca Ceresoli,
	kernel-team, Rob Herring, devicetree, linux-kernel
In-Reply-To: <CAGETcx-Emvu41nB3UDnb4Gh2aJEKu_hFcHX89uWnBTnaqvpN8g@mail.gmail.com>

On Mon, Mar 25, 2024 at 06:35:45PM -0700, Saravana Kannan wrote:
> Ok, I have a solution. Have the audio-graph-card2 find the fwnode of
> "multi" and mark it as "not a device" by doing something like this in
> the driver. That should help fw_devlink handle this correctly.
> 
> fwnode.flags |= FWNODE_FLAG_NOT_DEVICE;

I'll test this out, thanks.

> Definitely do this though as a forward looking improvement. It'll help
> make the suspend/resume more deterministic and will eventually let
> things happen in an async manner.

Is there a way to also do this in the driver?

> -Saravana

John.

^ permalink raw reply

* Re: [PATCH v6 09/15] media: bcm2835-unicam: Add support for CCP2/CSI2 camera interface
From: Laurent Pinchart @ 2024-03-26  1:37 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, Dave Stevenson, David Plowman, Jean-Michel Hautbois,
	Hans Verkuil, Naushir Patuck, kernel-list, linux-rpi-kernel,
	Florian Fainelli, Ray Jui, Scott Branden,
	bcm-kernel-feedback-list, Conor Dooley, Krzysztof Kozlowski,
	Rob Herring, devicetree
In-Reply-To: <ZgHEQTHZlRr_Rz6K@kekkonen.localdomain>

Hi Sakari,

On Mon, Mar 25, 2024 at 06:36:49PM +0000, Sakari Ailus wrote:
> On Fri, Mar 01, 2024 at 11:32:24PM +0200, Laurent Pinchart wrote:
> > From: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > 
> > Add a 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>
> > Co-developed-by: Naushir Patuck <naush@raspberrypi.com>
> > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> > Co-developed-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>
> > Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>
> > Co-developed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> Thanks for submitting this, it's the cleanest and neatest Unicom driver

Unicam, or if you insist Unicorn, but not Unicom :-)

> I've ever seen!
> 
> Some mostly unimportant comments below, however the bus-type issue needs to
> be addressed.
> 
> > ---
> > Changes since v5:
> > 
> > - Move to drivers/media/platform/broadcom/
> > - Port to the upstream V4L2 streams API
> > - Rebase on latest metadata API proposal
> > - Add missing error message
> > - Drop unneeded documentation block for unicam_isr()
> > - Drop unneeded dev_dbg() and dev_err() messages
> > - Drop unneeded streams_mask and fmt checks
> > - Drop unused unicam_sd_pad_is_sink()
> > - Drop unneeded includes
> > - Drop v4l2_ctrl_subscribe_event() call
> > - Use pm_runtime_resume_and_get()
> > - Indentation and line wrap fixes
> > - Let the framework set bus_info
> > - Use v4l2_fwnode_endpoint_parse()
> > - Fix media device cleanup
> > - Drop lane reordering checks
> > - Fix subdev state locking
> > - Drop extra debug messages
> > - Move clock handling to runtime PM handlers
> > - Reorder functions
> > - Rename init functions for more clarity
> > - Initialize runtime PM earlier
> > - Clarify error messages
> > - Simplify subdev init with local variable
> > - Fix subdev cleanup
> > - Fix typos and indentation
> > - Don't initialize local variables needlessly
> > - Simplify num lanes check
> > - Fix metadata handling in subdev set_fmt
> > - Drop manual fallback to .s_stream()
> > - Pass v4l2_pix_format to unicam_calc_format_size_bpl()
> > - Simplify unicam_set_default_format()
> > - Fix default format settings
> > - Add busy check in unicam_s_fmt_meta()
> > - Add missing \n at end of format strings
> > - Fix metadata handling in subdev set_fmt
> > - Fix locking when starting streaming
> > - Return buffers from start streaming fails
> > - Fix format validation for metadata node
> > - Use video_device_pipeline_{start,stop}() helpers
> > - Simplify format enumeration
> > - Drop unset variable
> > - Update MAINTAINERS entry
> > - Update to the upstream v4l2_async_nf API
> > - Update to the latest subdev routing API
> > - Update to the latest subdev state API
> > - Move from subdev .init_cfg() to .init_state()
> > - Update to the latest videobuf2 API
> > - Fix v4l2_subdev_enable_streams() error check
> > - Use correct pad for the connected subdev
> > - Return buffers to vb2 when start streaming fails
> > - Improve debugging in start streaming handler
> > - Simplify DMA address management
> > - Drop comment about bcm2835-camera driver
> > - Clarify comments that explain min/max sizes
> > - Pass v4l2_pix_format to unicam_try_fmt()
> > - Drop unneeded local variables
> > - Rename image-related constants and functions
> > - Turn unicam_fmt.metadata_fmt into bool
> > - Rename unicam_fmt to unicam_format_info
> > - Rename unicam_format_info variables to fmtinfo
> > - Rename unicam_node.v_fmt to fmt
> > - Add metadata formats for RAW10, RAW12 and RAW14
> > - Make metadata formats line-based
> > - Validate format on metadata video device
> > - Add Co-devlopped-by tags
> > 
> > Changes since v3:
> > 
> > - Add the vendor prefix for DT name
> > - Use the reg-names in DT parsing
> > - Remove MAINTAINERS entry
> > 
> > Changes since v2:
> > 
> > - Change code organization
> > - Remove unused variables
> > - Correct the fmt_meta functions
> > - Rewrite the start/stop streaming
> >   - You can now start the image node alone, but not the metadata one
> >   - The buffers are allocated per-node
> >   - only the required stream is started, if the route exists and is
> >     enabled
> > - Prefix the macros with UNICAM_ to not have too generic names
> > - Drop colorspace support
> > 
> > Changes since v1:
> > 
> > - Replace the unicam_{info,debug,error} macros with dev_*()
> > ---
> >  MAINTAINERS                                   |    1 +
> >  drivers/media/platform/Kconfig                |    1 +
> >  drivers/media/platform/Makefile               |    1 +
> >  drivers/media/platform/broadcom/Kconfig       |   23 +
> >  drivers/media/platform/broadcom/Makefile      |    3 +
> >  .../platform/broadcom/bcm2835-unicam-regs.h   |  255 ++
> >  .../media/platform/broadcom/bcm2835-unicam.c  | 2607 +++++++++++++++++
> >  7 files changed, 2891 insertions(+)
> >  create mode 100644 drivers/media/platform/broadcom/Kconfig
> >  create mode 100644 drivers/media/platform/broadcom/Makefile
> >  create mode 100644 drivers/media/platform/broadcom/bcm2835-unicam-regs.h
> >  create mode 100644 drivers/media/platform/broadcom/bcm2835-unicam.c
> > 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index e50a59654e6e..cc350729f467 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -4002,6 +4002,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 91e54215de3a..2d79bfc68c15 100644
> > --- a/drivers/media/platform/Kconfig
> > +++ b/drivers/media/platform/Kconfig
> > @@ -67,6 +67,7 @@ source "drivers/media/platform/amlogic/Kconfig"
> >  source "drivers/media/platform/amphion/Kconfig"
> >  source "drivers/media/platform/aspeed/Kconfig"
> >  source "drivers/media/platform/atmel/Kconfig"
> > +source "drivers/media/platform/broadcom/Kconfig"
> >  source "drivers/media/platform/cadence/Kconfig"
> >  source "drivers/media/platform/chips-media/Kconfig"
> >  source "drivers/media/platform/intel/Kconfig"
> > diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
> > index 3296ec1ebe16..da17301f7439 100644
> > --- a/drivers/media/platform/Makefile
> > +++ b/drivers/media/platform/Makefile
> > @@ -10,6 +10,7 @@ obj-y += amlogic/
> >  obj-y += amphion/
> >  obj-y += aspeed/
> >  obj-y += atmel/
> > +obj-y += broadcom/
> >  obj-y += cadence/
> >  obj-y += chips-media/
> >  obj-y += intel/
> > diff --git a/drivers/media/platform/broadcom/Kconfig b/drivers/media/platform/broadcom/Kconfig
> > new file mode 100644
> > index 000000000000..cc2c9afcc948
> > --- /dev/null
> > +++ b/drivers/media/platform/broadcom/Kconfig
> > @@ -0,0 +1,23 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +
> > +config VIDEO_BCM2835_UNICAM
> > +	tristate "Broadcom BCM283x/BCM271x Unicam video capture driver"
> > +	depends on ARCH_BCM2835 || COMPILE_TEST
> > +	depends on PM
> > +	depends on VIDEO_DEV
> > +	select MEDIA_CONTROLLER
> > +	select V4L2_FWNODE
> > +	select VIDEO_V4L2_SUBDEV_API
> > +	select VIDEOBUF2_DMA_CONTIG
> > +	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.
> > +
> > +	  To compile this driver as a module, choose M here. The module will be
> > +	  called bcm2835-unicam.
> > diff --git a/drivers/media/platform/broadcom/Makefile b/drivers/media/platform/broadcom/Makefile
> > new file mode 100644
> > index 000000000000..03d2045aba2e
> > --- /dev/null
> > +++ b/drivers/media/platform/broadcom/Makefile
> > @@ -0,0 +1,3 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +
> > +obj-$(CONFIG_VIDEO_BCM2835_UNICAM) += bcm2835-unicam.o
> > diff --git a/drivers/media/platform/broadcom/bcm2835-unicam-regs.h b/drivers/media/platform/broadcom/bcm2835-unicam-regs.h
> > new file mode 100644
> > index 000000000000..84775fd2fac5
> > --- /dev/null
> > +++ b/drivers/media/platform/broadcom/bcm2835-unicam-regs.h
> > @@ -0,0 +1,255 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +
> > +/*
> > + * Copyright (C) 2017-2020 Raspberry Pi Trading.
> 
> Anything up to 2024?

Not really. The registers haven't really changed :-) I'll update the
copyright in the .c file though.

> > + * Dave Stevenson <dave.stevenson@raspberrypi.com>
> > + */

[snip]

> > diff --git a/drivers/media/platform/broadcom/bcm2835-unicam.c b/drivers/media/platform/broadcom/bcm2835-unicam.c
> > new file mode 100644
> > index 000000000000..716c89b8a217
> > --- /dev/null
> > +++ b/drivers/media/platform/broadcom/bcm2835-unicam.c
> > @@ -0,0 +1,2607 @@

[snip]

> > +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 = unicam_reg_read(unicam, UNICAM_STA);
> > +	/* Write value back to clear the interrupts */
> > +	unicam_reg_write(unicam, UNICAM_STA, sta);
> > +
> > +	ista = unicam_reg_read(unicam, UNICAM_ISTA);
> > +	/* Write value back to clear the interrupts */
> > +	unicam_reg_write(unicam, UNICAM_ISTA, ista);
> > +
> > +	dev_dbg(unicam->dev, "ISR: ISTA: 0x%X, STA: 0x%X, sequence %d, lines done %d\n",
> > +		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;
> > +
> > +	/*
> > +	 * 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++;
> 
> Does access to this data need to be serialised somehow.

Given that it's only accessed from the interrupt handler (beside
start_streaming time, before starting the hardware), I don't think so.

> > +	}
> > +
> > +	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 (unicam_reg_read(unicam, UNICAM_ICTL) & UNICAM_FCM) {
> > +		/* Switch out of trigger mode if selected */
> > +		unicam_reg_write_field(unicam, UNICAM_ICTL, 1, UNICAM_TFC);
> > +		unicam_reg_write_field(unicam, UNICAM_ICTL, 0, UNICAM_FCM);
> > +	}
> > +	return IRQ_HANDLED;
> > +}
> > +
> > +static void unicam_set_packing_config(struct unicam_device *unicam)
> > +{
> > +	struct unicam_node *node = &unicam->node[UNICAM_IMAGE_NODE];
> > +	u32 pack, unpack;
> > +	u32 val;
> > +
> > +	if (node->fmt.fmt.pix.pixelformat == node->fmtinfo->fourcc) {
> > +		unpack = UNICAM_PUM_NONE;
> > +		pack = UNICAM_PPM_NONE;
> > +	} else {
> > +		switch (node->fmtinfo->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;
> 
> Also 8-bit data?

Not that I know of. The 8-bit entries in unicam_image_formats have no
.unpacked_fourcc field, so the condition in the if above will always be
true for those as they can only be selected by setting the pixel format
to fmtinfo->fourcc.

> > +	}
> > +
> > +	val = 0;
> 
> You could do initialisation in declaration.

Yes, but I think it's more readable to keep all the code that affects
the 'val' variable together.

> > +	unicam_set_field(&val, unpack, UNICAM_PUM_MASK);
> > +	unicam_set_field(&val, pack, UNICAM_PPM_MASK);
> > +	unicam_reg_write(unicam, UNICAM_IPIPE, val);
> > +}
> > +
> > +static void unicam_cfg_image_id(struct unicam_device *unicam)
> > +{
> > +	struct unicam_node *node = &unicam->node[UNICAM_IMAGE_NODE];
> > +
> > +	if (unicam->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > +		/* CSI2 mode, hardcode VC 0 for now. */
> > +		unicam_reg_write(unicam, UNICAM_IDI0,
> > +				 (0 << 6) | node->fmtinfo->csi_dt);
> > +	} else {
> > +		/* CCP2 mode */
> > +		unicam_reg_write(unicam, UNICAM_IDI0,
> > +				 0x80 | node->fmtinfo->csi_dt);
> > +	}
> > +}
> > +
> > +static void unicam_enable_ed(struct unicam_device *unicam)
> > +{
> > +	u32 val = unicam_reg_read(unicam, UNICAM_DCS);
> > +
> > +	unicam_set_field(&val, 2, UNICAM_EDL_MASK);
> > +	/* Do not wrap at the end of the embedded data buffer */
> > +	unicam_set_field(&val, 0, UNICAM_DBOB);
> > +
> > +	unicam_reg_write(unicam, UNICAM_DCS, val);
> > +}
> > +
> > +static void unicam_start_rx(struct unicam_device *unicam,
> > +			    struct unicam_buffer *buf)
> > +{
> > +	struct unicam_node *node = &unicam->node[UNICAM_IMAGE_NODE];
> > +	int line_int_freq = node->fmt.fmt.pix.height >> 2;
> > +	unsigned int i;
> > +	u32 val;
> > +
> > +	if (line_int_freq < 128)
> > +		line_int_freq = 128;
> 
> 	line_int_freq = max(line_int_freq, 128);
Ack.

> > +
> > +	/* Enable lane clocks */
> > +	val = 1;
> 
> Initialise in the loop initialisation below, I'd say.

How about

	val = 0x55 & GENMASK(unicam->pipe.num_data_lanes * 2 - 1, 0);

?

> > +	for (i = 0; i < unicam->active_data_lanes; i++)
> > +		val = val << 2 | 1;
> > +	unicam_clk_write(unicam, val);
> > +
> > +	/* Basic init */
> > +	unicam_reg_write(unicam, UNICAM_CTRL, UNICAM_MEM);
> > +
> > +	/* Enable analogue control, and leave in reset. */
> > +	val = UNICAM_AR;
> > +	unicam_set_field(&val, 7, UNICAM_CTATADJ_MASK);
> > +	unicam_set_field(&val, 7, UNICAM_PTATADJ_MASK);
> > +	unicam_reg_write(unicam, UNICAM_ANA, val);
> > +	usleep_range(1000, 2000);
> > +
> > +	/* Come out of reset */
> > +	unicam_reg_write_field(unicam, UNICAM_ANA, 0, UNICAM_AR);
> > +
> > +	/* Peripheral reset */
> > +	unicam_reg_write_field(unicam, UNICAM_CTRL, 1, UNICAM_CPR);
> > +	unicam_reg_write_field(unicam, UNICAM_CTRL, 0, UNICAM_CPR);
> > +
> > +	unicam_reg_write_field(unicam, UNICAM_CTRL, 0, UNICAM_CPE);
> > +
> > +	/* Enable Rx control. */
> > +	val = unicam_reg_read(unicam, UNICAM_CTRL);
> > +	if (unicam->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > +		unicam_set_field(&val, UNICAM_CPM_CSI2, UNICAM_CPM_MASK);
> > +		unicam_set_field(&val, UNICAM_DCM_STROBE, UNICAM_DCM_MASK);
> > +	} else {
> > +		unicam_set_field(&val, UNICAM_CPM_CCP2, UNICAM_CPM_MASK);
> > +		unicam_set_field(&val, unicam->bus_flags, UNICAM_DCM_MASK);
> > +	}
> > +	/* Packet framer timeout */
> > +	unicam_set_field(&val, 0xf, UNICAM_PFT_MASK);
> > +	unicam_set_field(&val, 128, UNICAM_OET_MASK);
> > +	unicam_reg_write(unicam, UNICAM_CTRL, val);
> > +
> > +	unicam_reg_write(unicam, UNICAM_IHWIN, 0);
> > +	unicam_reg_write(unicam, UNICAM_IVWIN, 0);
> > +
> > +	/* AXI bus access QoS setup */
> > +	val = unicam_reg_read(unicam, UNICAM_PRI);
> > +	unicam_set_field(&val, 0, UNICAM_BL_MASK);
> > +	unicam_set_field(&val, 0, UNICAM_BS_MASK);
> > +	unicam_set_field(&val, 0xe, UNICAM_PP_MASK);
> > +	unicam_set_field(&val, 8, UNICAM_NP_MASK);
> > +	unicam_set_field(&val, 2, UNICAM_PT_MASK);
> > +	unicam_set_field(&val, 1, UNICAM_PE);
> > +	unicam_reg_write(unicam, UNICAM_PRI, val);
> > +
> > +	unicam_reg_write_field(unicam, UNICAM_ANA, 0, UNICAM_DDL);
> > +
> > +	/* Always start in trigger frame capture mode (UNICAM_FCM set) */
> > +	val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM | UNICAM_IBOB;
> > +	unicam_set_field(&val, line_int_freq, UNICAM_LCIE_MASK);
> > +	unicam_reg_write(unicam, UNICAM_ICTL, val);
> > +	unicam_reg_write(unicam, UNICAM_STA, UNICAM_STA_MASK_ALL);
> > +	unicam_reg_write(unicam, UNICAM_ISTA, UNICAM_ISTA_MASK_ALL);
> > +
> > +	/* tclk_term_en */
> > +	unicam_reg_write_field(unicam, UNICAM_CLT, 2, UNICAM_CLT1_MASK);
> > +	/* tclk_settle */
> > +	unicam_reg_write_field(unicam, UNICAM_CLT, 6, UNICAM_CLT2_MASK);
> > +	/* td_term_en */
> > +	unicam_reg_write_field(unicam, UNICAM_DLT, 2, UNICAM_DLT1_MASK);
> > +	/* ths_settle */
> > +	unicam_reg_write_field(unicam, UNICAM_DLT, 6, UNICAM_DLT2_MASK);
> > +	/* trx_enable */
> > +	unicam_reg_write_field(unicam, UNICAM_DLT, 0, UNICAM_DLT3_MASK);
> > +
> > +	unicam_reg_write_field(unicam, UNICAM_CTRL, 0, UNICAM_SOE);
> > +
> > +	/* Packet compare setup - required to avoid missing frame ends */
> > +	val = 0;
> > +	unicam_set_field(&val, 1, UNICAM_PCE);
> > +	unicam_set_field(&val, 1, UNICAM_GI);
> > +	unicam_set_field(&val, 1, UNICAM_CPH);
> > +	unicam_set_field(&val, 0, UNICAM_PCVC_MASK);
> > +	unicam_set_field(&val, 1, UNICAM_PCDT_MASK);
> > +	unicam_reg_write(unicam, UNICAM_CMP0, val);
> > +
> > +	/* Enable clock lane and set up terminations */
> > +	val = 0;
> > +	if (unicam->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > +		/* CSI2 */
> > +		unicam_set_field(&val, 1, UNICAM_CLE);
> > +		unicam_set_field(&val, 1, UNICAM_CLLPE);
> > +		if (!(unicam->bus_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)) {
> > +			unicam_set_field(&val, 1, UNICAM_CLTRE);
> > +			unicam_set_field(&val, 1, UNICAM_CLHSE);
> > +		}
> > +	} else {
> > +		/* CCP2 */
> > +		unicam_set_field(&val, 1, UNICAM_CLE);
> > +		unicam_set_field(&val, 1, UNICAM_CLHSE);
> > +		unicam_set_field(&val, 1, UNICAM_CLTRE);
> > +	}
> > +	unicam_reg_write(unicam, 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 (unicam->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > +		/* CSI2 */
> > +		unicam_set_field(&val, 1, UNICAM_DLE);
> > +		unicam_set_field(&val, 1, UNICAM_DLLPE);
> > +		if (!(unicam->bus_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)) {
> > +			unicam_set_field(&val, 1, UNICAM_DLTRE);
> > +			unicam_set_field(&val, 1, UNICAM_DLHSE);
> > +		}
> > +	} else {
> > +		/* CCP2 */
> > +		unicam_set_field(&val, 1, UNICAM_DLE);
> > +		unicam_set_field(&val, 1, UNICAM_DLHSE);
> > +		unicam_set_field(&val, 1, UNICAM_DLTRE);
> > +	}
> > +	unicam_reg_write(unicam, UNICAM_DAT0, val);
> > +
> > +	if (unicam->active_data_lanes == 1)
> > +		val = 0;
> > +	unicam_reg_write(unicam, UNICAM_DAT1, val);
> > +
> > +	if (unicam->max_data_lanes > 2) {
> > +		/*
> > +		 * Registers UNICAM_DAT2 and UNICAM_DAT3 only valid if the
> > +		 * instance supports more than 2 data lanes.
> > +		 */
> > +		if (unicam->active_data_lanes == 2)
> > +			val = 0;
> > +		unicam_reg_write(unicam, UNICAM_DAT2, val);
> > +
> > +		if (unicam->active_data_lanes == 3)
> > +			val = 0;
> > +		unicam_reg_write(unicam, UNICAM_DAT3, val);
> > +	}
> > +
> > +	unicam_reg_write(unicam, UNICAM_IBLS,
> > +			 node->fmt.fmt.pix.bytesperline);
> > +	unicam_wr_dma_addr(&unicam->node[UNICAM_IMAGE_NODE], buf);
> > +	unicam_set_packing_config(unicam);
> > +	unicam_cfg_image_id(unicam);
> > +
> > +	val = unicam_reg_read(unicam, UNICAM_MISC);
> > +	unicam_set_field(&val, 1, UNICAM_FL0);
> > +	unicam_set_field(&val, 1, UNICAM_FL1);
> > +	unicam_reg_write(unicam, UNICAM_MISC, val);
> > +
> > +	/* Enable peripheral */
> > +	unicam_reg_write_field(unicam, UNICAM_CTRL, 1, UNICAM_CPE);
> > +
> > +	/* Load image pointers */
> > +	unicam_reg_write_field(unicam, UNICAM_ICTL, 1, UNICAM_LIP_MASK);
> > +
> > +	/*
> > +	 * Enable trigger only for the first frame to
> > +	 * sync correctly to the FS from the source.
> > +	 */
> > +	unicam_reg_write_field(unicam, UNICAM_ICTL, 1, UNICAM_TFC);
> > +}

[snip]

> > +static int unicam_async_nf_init(struct unicam_device *unicam)
> > +{
> > +	struct v4l2_fwnode_endpoint ep = { };
> 
> If the bus-type property is mandatory and you have no stated defaults
> anywhere, this is fine. I.e. all the relevant properties would need to be
> mandatory.

They are, as far as I can tell (well, the clock-noncontinuous property
is not mandatory, but that's expected as it's a flag).

> > +	struct fwnode_handle *ep_handle;
> > +	struct v4l2_async_connection *asc;
> > +	int ret;
> > +
> > +	ret = of_property_read_u32(unicam->dev->of_node, "brcm,num-data-lanes",
> > +				   &unicam->max_data_lanes);
> > +	if (ret < 0) {
> > +		dev_err(unicam->dev, "Missing %s DT property\n",
> > +			"brcm,num-data-lanes");
> > +		return -EINVAL;
> > +	}
> > +
> > +	/* Get and parse the local endpoint. */
> > +	ep_handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(unicam->dev), 0, 0,
> > +						    FWNODE_GRAPH_ENDPOINT_NEXT);
> > +	if (!ep_handle) {
> > +		dev_err(unicam->dev, "No endpoint found\n");
> > +		return -ENODEV;
> > +	}
> > +
> > +	ret = v4l2_fwnode_endpoint_parse(ep_handle, &ep);
> > +	if (ret) {
> > +		dev_err(unicam->dev, "Failed to parse endpoint: %d\n", ret);
> > +		goto error;
> > +	}
> > +
> > +	unicam->bus_type = ep.bus_type;
> > +
> > +	switch (ep.bus_type) {
> > +	case V4L2_MBUS_CSI2_DPHY: {
> > +		unsigned int num_data_lanes = ep.bus.mipi_csi2.num_data_lanes;
> > +
> > +		if (num_data_lanes != 1 && num_data_lanes != 2 &&
> > +		    num_data_lanes != 4) {
> > +			dev_err(unicam->dev, "%u data lanes not supported\n",
> > +				num_data_lanes);
> > +			goto error;
> > +		}
> > +
> > +		if (num_data_lanes > unicam->max_data_lanes) {
> > +			dev_err(unicam->dev,
> > +				"Endpoint uses %u data lanes when %u are supported\n",
> > +				num_data_lanes, unicam->max_data_lanes);
> > +			goto error;
> > +		}
> > +
> > +		unicam->active_data_lanes = num_data_lanes;
> > +		unicam->bus_flags = ep.bus.mipi_csi2.flags;
> > +		break;
> > +	}
> > +
> > +	case V4L2_MBUS_CCP2:
> > +		unicam->max_data_lanes = 1;
> > +		unicam->active_data_lanes = 1;
> > +		unicam->bus_flags = ep.bus.mipi_csi1.strobe;
> > +		break;
> > +
> > +	default:
> > +		/* Unsupported bus type */
> > +		dev_err(unicam->dev, "Unsupported bus type %u\n", ep.bus_type);
> > +		goto error;
> > +	}
> > +
> > +	/* Initialize and register the async notifier. */
> > +	v4l2_async_nf_init(&unicam->notifier, &unicam->v4l2_dev);
> > +
> > +	asc = v4l2_async_nf_add_fwnode_remote(&unicam->notifier, ep_handle,
> > +					      struct v4l2_async_connection);
> > +	fwnode_handle_put(ep_handle);
> > +	ep_handle = NULL;
> > +
> > +	if (IS_ERR(asc)) {
> > +		ret = PTR_ERR(asc);
> > +		dev_err(unicam->dev, "Failed to add entry to notifier: %d\n",
> > +			ret);
> > +		goto error;
> > +	}
> > +
> > +	unicam->notifier.ops = &unicam_async_ops;
> > +
> > +	ret = v4l2_async_nf_register(&unicam->notifier);
> > +	if (ret) {
> > +		dev_err(unicam->dev, "Error registering device notifier: %d\n",
> > +			ret);
> > +		goto error;
> > +	}
> > +
> > +	return 0;
> > +
> > +error:
> > +	fwnode_handle_put(ep_handle);
> > +	return ret;
> > +}
> > +
> > +/* -----------------------------------------------------------------------------
> > + * Probe & remove
> > + */
> > +
> > +static int unicam_media_init(struct unicam_device *unicam)
> > +{
> > +	int ret;
> > +
> > +	unicam->mdev.dev = unicam->dev;
> > +	strscpy(unicam->mdev.model, UNICAM_MODULE_NAME,
> > +		sizeof(unicam->mdev.model));
> > +	strscpy(unicam->mdev.serial, "", sizeof(unicam->mdev.serial));
> 
> Isn't the field already zeroed?

Indeed. I'll drop this.

> 
> > +	unicam->mdev.hw_revision = 0;
> > +
> > +	media_device_init(&unicam->mdev);
> > +
> > +	unicam->v4l2_dev.mdev = &unicam->mdev;
> > +
> > +	ret = v4l2_device_register(unicam->dev, &unicam->v4l2_dev);
> > +	if (ret < 0) {
> > +		dev_err(unicam->dev, "Unable to register v4l2 device\n");
> > +		goto err_media_cleanup;
> > +	}
> > +
> > +	ret = media_device_register(&unicam->mdev);
> > +	if (ret < 0) {
> > +		dev_err(unicam->dev,
> > +			"Unable to register media-controller device\n");
> > +		goto err_v4l2_unregister;
> > +	}
> > +
> > +	return 0;
> > +
> > +err_v4l2_unregister:
> > +	v4l2_device_unregister(&unicam->v4l2_dev);
> > +err_media_cleanup:
> > +	media_device_cleanup(&unicam->mdev);
> > +	return ret;
> > +}

[snip]

-- 
Regards,

Laurent Pinchart

^ permalink raw reply


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