Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v2 3/3] arm64: dts: freescale: Add device tree for Emcraft Systems NavQ+ Kit
From: Andrew Lunn @ 2024-03-30 16:46 UTC (permalink / raw)
  To: Gilles Talis
  Cc: devicetree, imx, linux-arm-kernel, conor+dt,
	krzysztof.kozlowski+dt, robh, shawnguo, festevam, alex
In-Reply-To: <20240330133410.41408-4-gilles.talis@gmail.com>

> +&eqos {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pinctrl_eqos>;
> +	phy-mode = "rgmii-id";
> +	phy-handle = <&ethphy0>;
> +	status = "okay";
> +
> +	mdio {
> +		compatible = "snps,dwmac-mdio";
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		ethphy0: ethernet-phy@0 {
> +			compatible = "ethernet-phy-ieee802.3-c22";
> +			reg = <0>;
> +			reset-gpios = <&gpio4 22 GPIO_ACTIVE_LOW>;
> +			reset-assert-us = <1000>;
> +			reset-deassert-us = <10000>;
> +			qca,disable-smarteee;
> +			qca,disable-hibernation-mode;
> +		};
> +	};
> +};

Thanks for removing the regulator.

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

^ permalink raw reply

* Re: [PATCH 3/3] dt-bindings: adc: Document XuanTie TH1520 ADC
From: Jonathan Cameron @ 2024-03-30 16:14 UTC (permalink / raw)
  To: wefu
  Cc: jszhang, guoren, conor, robh, krzysztof.kozlowski+dt,
	paul.walmsley, palmer, aou, lars, andriy.shevchenko, nuno.sa,
	marcelo.schmitt, bigunclemax, marius.cristea, fr0st61te,
	okan.sahin, marcus.folkesson, schnelle, lee, mike.looijmans,
	linux-riscv, devicetree, linux-kernel, linux-iio
In-Reply-To: <20240329200241.4122000-4-wefu@redhat.com>

On Sat, 30 Mar 2024 04:01:26 +0800
wefu@redhat.com wrote:

> From: Wei Fu <wefu@redhat.com>
> 
> Document devicetree bindings for the XuanTie TH1520 AP sub-system ADC.
> 
> Signed-off-by: Wei Fu <wefu@redhat.com>

Hi.

Few comments inline.

Given Fugang Duan is listed as a maintainer I'd also like an ack ideally
from them.  BTW your +CC list seems a bit random.


Thanks,

Jonathan


> ---
>  .../bindings/iio/adc/thead,th1520.yaml        | 52 +++++++++++++++++++
>  1 file changed, 52 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/iio/adc/thead,th1520.yaml b/Documentation/devicetree/bindings/iio/adc/thead,th1520.yaml
> new file mode 100644
> index 000000000000..80890ce62810
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/adc/thead,th1520.yaml
> @@ -0,0 +1,52 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/iio/adc/thead,th1520.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: XuanTie TH1520 Analog to Digital Converter (ADC)
> +
> +maintainers:
> +  - Fugang Duan <duanfugang.dfg@linux.alibaba.com>
> +  - Wei Fu <wefu@redhat.com>
> +
> +description: |
> +  12-Bit Analog to Digital Converter (ADC) on XuanTie TH1520
> +
> +properties:
> +  compatible:
> +    const: thead,th1520

See the example - doesn't match.  Should be -adc here as well
as this is just part of the SoC.


> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +
> +  clock-names:
> +    const: adc

No objection to having names, but if there is only 1 why is
it required?

> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - clocks
> +  - clock-names
> +  - status

Status doesn't need to be here

> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    adc: adc@0xfffff51000 {
> +	compatible = "thead,th1520-adc";

As the bot pointed out, spaces not tabs for these - Please run the suggested
tests in that email before sending a v2.

> +	reg = <0xff 0xfff51000 0x0 0x1000>;
> +	interrupts = <61 IRQ_TYPE_LEVEL_HIGH>;
> +	clocks = <&aonsys_clk>;
> +	clock-names = "adc";
> +	/* ADC pin is proprietary,no need to config pinctrl */
> +	status = "disabled";
No need for a status entry in the example.


> +    };


^ permalink raw reply

* Re: [PATCH 2/2] dt-bindings: iio: imu: add icm42688 inside inv_icm42600
From: Jonathan Cameron @ 2024-03-30 16:10 UTC (permalink / raw)
  To: Conor Dooley
  Cc: inv.git-commit, robh, krzysztof.kozlowski+dt, conor+dt, lars,
	linux-iio, devicetree, Jean-Baptiste Maneyrol
In-Reply-To: <20240329-fifth-earpiece-78daf4d943ce@spud>

On Fri, 29 Mar 2024 15:49:26 +0000
Conor Dooley <conor@kernel.org> wrote:

> On Fri, Mar 29, 2024 at 03:15:35PM +0000, inv.git-commit@tdk.com wrote:
> > From: Jean-Baptiste Maneyrol <jean-baptiste.maneyrol@tdk.com>
> > 
> > Add bindings for ICM-42688-P chip.
> > 
> > Signed-off-by: Jean-Baptiste Maneyrol <jean-baptiste.maneyrol@tdk.com>  
> 
> My initial thought was that you're missing a sign-off, but is
> "inv.git-commit@tdk.com" some system you have to bypass corporate email
> garbage?

Common enough setup, as long as the From: line matches the sign-off, git will
ignore the email address used to send it when the patch is applied.

> 
> > ---
> >  .../devicetree/bindings/iio/imu/invensense,icm42600.yaml         | 1 +
> >  1 file changed, 1 insertion(+)
> > 
> > diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
> > index 7cd05bcbee31..152aec8d82ff 100644
> > --- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
> > +++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
> > @@ -31,6 +31,7 @@ properties:
> >        - invensense,icm42602
> >        - invensense,icm42605
> >        - invensense,icm42622
> > +      - invensense,icm42688  
> 
> Can you add this in alphanumerical order please?
> 
> Also, this patch should be the first in the series.

Agreed on both, otherwise this series LGTM

Jonathan

> 
> Thanks,
> Conor.
> 
> >        - invensense,icm42631
> > 
> >    reg:
> > --
> > 2.34.1
> >   


^ permalink raw reply

* Re: [PATCH 3/3] arm64: dts: rockchip: Remove UART2 from RGB30
From: Chris Morgan @ 2024-03-30 15:34 UTC (permalink / raw)
  To: Ahmad Fatoum
  Cc: Chris Morgan, linux-rockchip, linux-clk, devicetree, sboyd,
	mturquette, heiko, conor+dt, krzysztof.kozlowski+dt, robh+dt
In-Reply-To: <7c7138f8-b0b7-46c3-b7b2-84e01467f368@pengutronix.de>

On Sat, Mar 30, 2024 at 02:13:05PM +0100, Ahmad Fatoum wrote:
> Hello Chris,
> 
> On 18.10.23 17:33, Chris Morgan wrote:
> > From: Chris Morgan <macromorgan@hotmail.com>
> > 
> > The Powkiddy RGB30 has no onboard UART header, so remove the reference
> > to it in the device tree. This was left on by mistake in the initial
> > commit.
> 
> Do you know if the UART is perhaps available over testpoints?

There is not one as best I can tell on either the RGB30 or RK2023. The
Powkiddy X55 does have UART, however. I was able to exploit the fact
that the RGB30 is extremely similar to all of the Anbernic devices
(such as the RG353 series) for the purposes of low-level development.
Once I got a network connection I performed the rest of development
over SSH, but prior to that I just developed on a different device.

Thank you,
Chris.

> 
> If yes, having a DT-overlay upstream enabling it along with documentation could be useful.
> If not, how do you do low-level debugging on the RBG30 in absence of the serial console?
> 
> Thanks,
> Ahmad 
> 
> > 
> > Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
> > ---
> >  arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb30.dts | 9 +++++++++
> >  1 file changed, 9 insertions(+)
> > 
> > diff --git a/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb30.dts b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb30.dts
> > index 3ebc21608213..1ead3c5c24b3 100644
> > --- a/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb30.dts
> > +++ b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb30.dts
> > @@ -64,6 +64,10 @@ simple-audio-card,cpu {
> >  
> >  /delete-node/ &adc_keys;
> >  
> > +&chosen {
> > +	/delete-property/ stdout-path;
> > +};
> > +
> >  &cru {
> >  	assigned-clocks = <&pmucru CLK_RTC_32K>, <&cru PLL_GPLL>,
> >  			  <&pmucru PLL_PPLL>, <&cru PLL_VPLL>;
> > @@ -149,4 +153,9 @@ rk817_charger: charger {
> >  	};
> >  };
> >  
> > +/* There is no UART header visible on the board for this device. */
> > +&uart2 {
> > +	status = "disabled";
> > +};
> > +
> >  /delete-node/ &vibrator;
> 
> -- 
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> 

^ permalink raw reply

* Re: [PATCH v6 7/7] iio: accel: adxl345: Add spi-3wire option
From: Jonathan Cameron @ 2024-03-30 15:29 UTC (permalink / raw)
  To: Lothar Rubusch
  Cc: lars, Michael.Hennerich, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, linux-iio, devicetree, linux-kernel, eraretuya
In-Reply-To: <20240329004030.16153-8-l.rubusch@gmail.com>

On Fri, 29 Mar 2024 00:40:30 +0000
Lothar Rubusch <l.rubusch@gmail.com> wrote:

> Add a setup function implementation to the spi module to enable spi-3wire
> when specified in the device-tree.
> 
> Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
> ---
>  drivers/iio/accel/adxl345.h     |  1 +
>  drivers/iio/accel/adxl345_spi.c | 12 +++++++++++-
>  2 files changed, 12 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h
> index e859c01d4..3d5c8719d 100644
> --- a/drivers/iio/accel/adxl345.h
> +++ b/drivers/iio/accel/adxl345.h
> @@ -31,6 +31,7 @@
>  #define ADXL345_DATA_FORMAT_RANGE	GENMASK(1, 0)	/* Set the g range */
>  #define ADXL345_DATA_FORMAT_JUSTIFY	BIT(2)	/* Left-justified (MSB) mode */
>  #define ADXL345_DATA_FORMAT_FULL_RES	BIT(3)	/* Up to 13-bits resolution */
> +#define ADXL345_DATA_FORMAT_SPI_3WIRE	BIT(6)	/* 3-wire SPI mode */
>  #define ADXL345_DATA_FORMAT_SELF_TEST	BIT(7)	/* Enable a self test */
>  
>  #define ADXL345_DATA_FORMAT_2G		0
> diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c
> index 1c0513bd3..f145d5c1d 100644
> --- a/drivers/iio/accel/adxl345_spi.c
> +++ b/drivers/iio/accel/adxl345_spi.c
> @@ -20,6 +20,16 @@ static const struct regmap_config adxl345_spi_regmap_config = {
>  	.read_flag_mask = BIT(7) | BIT(6),
>  };
>  
> +static int adxl345_spi_setup(struct device *dev, struct regmap *regmap)
> +{
> +	struct spi_device *spi = container_of(dev, struct spi_device, dev);
> +
> +	if (spi->mode & SPI_3WIRE)
> +		return regmap_write(regmap, ADXL345_REG_DATA_FORMAT,
> +				    ADXL345_DATA_FORMAT_SPI_3WIRE);
My only remaining comment on this patch set is to add equivalent of
	else
		return regmap_write(regmap, ADXL345_REG_DATA_FORMAT, 0);

If the hardware had some sort of software reset, that was used,
this wouldn't be needed as the status of those other bits would be known.
If we leave them alone in the non 3wire path we may in the future have
subtle issues because some other code left this in an odd state and
we clear those other bits only for 3wire mode.

Jonathan

> +	return 0;
> +}
> +
>  static int adxl345_spi_probe(struct spi_device *spi)
>  {
>  	struct regmap *regmap;
> @@ -33,7 +43,7 @@ static int adxl345_spi_probe(struct spi_device *spi)
>  	if (IS_ERR(regmap))
>  		return dev_err_probe(&spi->dev, PTR_ERR(regmap), "Error initializing regmap\n");
>  
> -	return adxl345_core_probe(&spi->dev, regmap, NULL);
> +	return adxl345_core_probe(&spi->dev, regmap, adxl345_spi_setup);
>  }
>  
>  static const struct adxl345_chip_info adxl345_spi_info = {


^ permalink raw reply

* Re: [PATCH v5 7/7] iio: accel: adxl345: Add spi-3wire option
From: Jonathan Cameron @ 2024-03-30 15:24 UTC (permalink / raw)
  To: Lothar Rubusch
  Cc: lars, Michael.Hennerich, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, linux-iio, devicetree, linux-kernel, eraretuya
In-Reply-To: <CAFXKEHZva5AE=sinx_i0Gec2FbB4ZfyEu8mWg52omzGBvr5uXw@mail.gmail.com>

On Fri, 29 Mar 2024 01:33:01 +0100
Lothar Rubusch <l.rubusch@gmail.com> wrote:

> On Thu, Mar 28, 2024 at 2:39 PM Jonathan Cameron <jic23@kernel.org> wrote:
> >
> > On Wed, 27 Mar 2024 22:03:20 +0000
> > Lothar Rubusch <l.rubusch@gmail.com> wrote:
> >  
> > > Add a setup function implementation to the spi module to enable spi-3wire
> > > as option when specified in the device-tree.
> > >
> > > Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
> > > ---
> > >  drivers/iio/accel/adxl345.h     |  2 ++
> > >  drivers/iio/accel/adxl345_spi.c | 12 +++++++++++-
> > >  2 files changed, 13 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/iio/accel/adxl345.h b/drivers/iio/accel/adxl345.h
> > > index 4ea9341d4..e6bc3591c 100644
> > > --- a/drivers/iio/accel/adxl345.h
> > > +++ b/drivers/iio/accel/adxl345.h
> > > @@ -30,6 +30,8 @@
> > >  #define ADXL345_POWER_CTL_MEASURE    BIT(3)
> > >  #define ADXL345_POWER_CTL_STANDBY    0x00
> > >
> > > +#define ADXL345_DATA_FORMAT_SPI_3WIRE        BIT(6) /* 3-wire SPI mode */
> > > +
> > >  #define ADXL345_DATA_FORMAT_RANGE    GENMASK(1, 0) /* Set the g range */
> > >  #define ADXL345_DATA_FORMAT_JUSTIFY  BIT(2) /* Left-justified (MSB) mode */
> > >  #define ADXL345_DATA_FORMAT_FULL_RES BIT(3) /* Up to 13-bits resolution */
> > > diff --git a/drivers/iio/accel/adxl345_spi.c b/drivers/iio/accel/adxl345_spi.c
> > > index 1c0513bd3..f145d5c1d 100644
> > > --- a/drivers/iio/accel/adxl345_spi.c
> > > +++ b/drivers/iio/accel/adxl345_spi.c
> > > @@ -20,6 +20,16 @@ static const struct regmap_config adxl345_spi_regmap_config = {
> > >       .read_flag_mask = BIT(7) | BIT(6),
> > >  };
> > >
> > > +static int adxl345_spi_setup(struct device *dev, struct regmap *regmap)
> > > +{
> > > +     struct spi_device *spi = container_of(dev, struct spi_device, dev);
> > > +
> > > +     if (spi->mode & SPI_3WIRE)
> > > +             return regmap_write(regmap, ADXL345_REG_DATA_FORMAT,
> > > +                                 ADXL345_DATA_FORMAT_SPI_3WIRE);  
> > Your earlier patch carefully (I think) left one or two fields alone, then
> > this write just comes in and changes them. In particular INT_INVERT.
> >  
> Why do you refer here to INT_INVERT? In this code above I try to set
> SPI to 3 lines. Since this is a SPI configuration, i.e. bus specific,
> it happens in adxl345_spi.c. Passing this function to the bus
> independent adxl345_core.c file allows to configure the bus first.
> Therefore, I'm using the update function in core masking out the SPI
> filag.

Ah. Ok.  It was only intended to mask out the SPI3-wire bit, not the
other bits that you also masked out.  I thought intent was to leave
them untouched for some reason.  Given they don't matter in the driver
at the moment (no interrupt support) then no problem.

> 
> My reason why I try to keep INT_INVERT out is different. There is
> another driver for the same part in the kernel:
> ./drivers/input/misc/adxl34x.c - This is a input driver, using the
> interrupts of the adxl345 for the input device implementation. I
> assumed, that in the iio implementation there won't be interrupt
> handling for the adx345, since it is not an input device. Does this
> make sense?

No. You can't use these two drivers at the same time.  They will almost
certainly trample over each other in actually reading channels etc.

Their is some legacy of old drivers in input from a long time back.
Given this driver clearly doesn't have full functionality yet in IIO there
and the different userspace ABI, we've just left the input driver alone.

> 
> > If it doesn't makes sense to write it there, either write that bit
> > every time here, or leave it alone every time.  Not decide on whether
> > to write the bit based on SPI_3WIRE or not.  As far as I know they
> > are unconnected features.
> >  
> I think I did not understand. Could you please specify a bit more?
> When spi-3wire is configured in the DT it has to be parsed and handled
> in the bus specific part, i.e. the adxl345_spi.c Therefore I configure
> SPI_3WIRE there. I don't want to place SPI specific code in the core
> file.

My confusion was that you were deliberately not touching the other unused
flags.  In reality you are touching the but only if you enable 3wire.
I would write them register to 0 in the !3wire case so all other values
are the same in both paths.

> 
> > > +     return 0;
> > > +}
> > > +
> > >  static int adxl345_spi_probe(struct spi_device *spi)
> > >  {
> > >       struct regmap *regmap;
> > > @@ -33,7 +43,7 @@ static int adxl345_spi_probe(struct spi_device *spi)
> > >       if (IS_ERR(regmap))
> > >               return dev_err_probe(&spi->dev, PTR_ERR(regmap), "Error initializing regmap\n");
> > >
> > > -     return adxl345_core_probe(&spi->dev, regmap, NULL);
> > > +     return adxl345_core_probe(&spi->dev, regmap, adxl345_spi_setup);
> > >  }
> > >
> > >  static const struct adxl345_chip_info adxl345_spi_info = {  
> >  


^ permalink raw reply

* [PATCH v5 0/2] backlight: Add new lm3509 backlight driver
From: Patrick Gansterer @ 2024-03-30 14:59 UTC (permalink / raw)
  To: dri-devel, linux-leds, devicetree, linux-kernel, linux-fbdev
  Cc: Patrick Gansterer, Lee Jones, Daniel Thompson, Jingoo Han,
	Pavel Machek, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Helge Deller, Sam Ravnborg

This is a general driver for LM3509 backlight chip of TI.
LM3509 is High Efficiency Boost for White LEDs and/or OLED Displays with
Dual Current Sinks. This driver supports OLED/White LED select, brightness
control and sub/main control.
The datasheet can be found at http://www.ti.com/product/lm3509.
---
Changes in v5:
  Renamed lm3509_bl_led_pdata to lm3509_bl_led_data
  Set backlight_properties.scale to BACKLIGHT_SCALE_NON_LINEAR
  Add dev_err_probe() for first write to a register
  Use dev_err_probe() instead of dev_err()

v4: https://lore.kernel.org/all/20240310135344.3455294-1-paroga@paroga.com/

Changes in v4:
  Use backlight_*() to access backlight_device
  Do not set backlight_properties.power

v3: https://lore.kernel.org/all/20240309132521.1290173-1-paroga@paroga.com/

Changes in v3:
  Improved device tree bindings documentation

v2: https://lore.kernel.org/all/20240308215617.1729664-1-paroga@paroga.com/

Changes in v2:
  Add device tree nodes for each output
  Addressed multiple smaller review comments

v1: https://lore.kernel.org/all/20240302212757.1871164-1-paroga@paroga.com/

Patrick Gansterer (2):
  dt-bindings: backlight: Add Texas Instruments LM3509
  backlight: Add new lm3509 backlight driver

 .../bindings/leds/backlight/ti,lm3509.yaml    | 139 +++++++
 drivers/video/backlight/Kconfig               |   7 +
 drivers/video/backlight/Makefile              |   1 +
 drivers/video/backlight/lm3509_bl.c           | 340 ++++++++++++++++++
 4 files changed, 487 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/backlight/ti,lm3509.yaml
 create mode 100644 drivers/video/backlight/lm3509_bl.c

-- 
2.44.0


^ permalink raw reply

* [PATCH v5 2/2] backlight: Add new lm3509 backlight driver
From: Patrick Gansterer @ 2024-03-30 14:59 UTC (permalink / raw)
  To: dri-devel, linux-leds, devicetree, linux-kernel, linux-fbdev
  Cc: Patrick Gansterer, Lee Jones, Daniel Thompson, Jingoo Han,
	Pavel Machek, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Helge Deller, Sam Ravnborg
In-Reply-To: <20240330145931.729116-1-paroga@paroga.com>

This is a general driver for LM3509 backlight chip of TI.
LM3509 is High Efficiency Boost for White LEDs and/or OLED Displays with
Dual Current Sinks. This driver supports OLED/White LED select, brightness
control and sub/main control.
The datasheet can be found at http://www.ti.com/product/lm3509.

Signed-off-by: Patrick Gansterer <paroga@paroga.com>
---
 drivers/video/backlight/Kconfig     |   7 +
 drivers/video/backlight/Makefile    |   1 +
 drivers/video/backlight/lm3509_bl.c | 340 ++++++++++++++++++++++++++++
 3 files changed, 348 insertions(+)
 create mode 100644 drivers/video/backlight/lm3509_bl.c

diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 230bca07b09d..3614a5d29c71 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -373,6 +373,13 @@ config BACKLIGHT_AAT2870
 	  If you have a AnalogicTech AAT2870 say Y to enable the
 	  backlight driver.
 
+config BACKLIGHT_LM3509
+	tristate "Backlight Driver for LM3509"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  This supports TI LM3509 Backlight Driver
+
 config BACKLIGHT_LM3630A
 	tristate "Backlight Driver for LM3630A"
 	depends on I2C && PWM
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 8d2cb252042d..8fc98f760a8a 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_BACKLIGHT_IPAQ_MICRO)	+= ipaq_micro_bl.o
 obj-$(CONFIG_BACKLIGHT_KTD253)		+= ktd253-backlight.o
 obj-$(CONFIG_BACKLIGHT_KTD2801)		+= ktd2801-backlight.o
 obj-$(CONFIG_BACKLIGHT_KTZ8866)		+= ktz8866.o
+obj-$(CONFIG_BACKLIGHT_LM3509)		+= lm3509_bl.o
 obj-$(CONFIG_BACKLIGHT_LM3533)		+= lm3533_bl.o
 obj-$(CONFIG_BACKLIGHT_LM3630A)		+= lm3630a_bl.o
 obj-$(CONFIG_BACKLIGHT_LM3639)		+= lm3639_bl.o
diff --git a/drivers/video/backlight/lm3509_bl.c b/drivers/video/backlight/lm3509_bl.c
new file mode 100644
index 000000000000..ab57f79ffe23
--- /dev/null
+++ b/drivers/video/backlight/lm3509_bl.c
@@ -0,0 +1,340 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#define LM3509_NAME "lm3509_bl"
+
+#define LM3509_SINK_MAIN 0
+#define LM3509_SINK_SUB 1
+#define LM3509_NUM_SINKS 2
+
+#define LM3509_DEF_BRIGHTNESS 0x12
+#define LM3509_MAX_BRIGHTNESS 0x1F
+
+#define REG_GP 0x10
+#define REG_BMAIN 0xA0
+#define REG_BSUB 0xB0
+#define REG_MAX 0xFF
+
+enum {
+	REG_GP_ENM_BIT = 0,
+	REG_GP_ENS_BIT,
+	REG_GP_UNI_BIT,
+	REG_GP_RMP0_BIT,
+	REG_GP_RMP1_BIT,
+	REG_GP_OLED_BIT,
+};
+
+struct lm3509_bl {
+	struct regmap *regmap;
+	struct backlight_device *bl_main;
+	struct backlight_device *bl_sub;
+	struct gpio_desc *reset_gpio;
+};
+
+struct lm3509_bl_led_data {
+	const char *label;
+	int led_sources;
+	u32 brightness;
+	u32 max_brightness;
+};
+
+static void lm3509_reset(struct lm3509_bl *data)
+{
+	if (data->reset_gpio) {
+		gpiod_set_value(data->reset_gpio, 1);
+		udelay(1);
+		gpiod_set_value(data->reset_gpio, 0);
+		udelay(10);
+	}
+}
+
+static int lm3509_update_status(struct backlight_device *bl,
+				unsigned int en_mask, unsigned int br_reg)
+{
+	struct lm3509_bl *data = bl_get_data(bl);
+	int ret;
+	bool en;
+
+	ret = regmap_write(data->regmap, br_reg, backlight_get_brightness(bl));
+	if (ret < 0)
+		return ret;
+
+	en = !backlight_is_blank(bl);
+	return regmap_update_bits(data->regmap, REG_GP, en_mask,
+				  en ? en_mask : 0);
+}
+
+static int lm3509_main_update_status(struct backlight_device *bl)
+{
+	return lm3509_update_status(bl, BIT(REG_GP_ENM_BIT), REG_BMAIN);
+}
+
+static const struct backlight_ops lm3509_main_ops = {
+	.options = BL_CORE_SUSPENDRESUME,
+	.update_status = lm3509_main_update_status,
+};
+
+static int lm3509_sub_update_status(struct backlight_device *bl)
+{
+	return lm3509_update_status(bl, BIT(REG_GP_ENS_BIT), REG_BSUB);
+}
+
+static const struct backlight_ops lm3509_sub_ops = {
+	.options = BL_CORE_SUSPENDRESUME,
+	.update_status = lm3509_sub_update_status,
+};
+
+static struct backlight_device *
+lm3509_backlight_register(struct device *dev, const char *name_suffix,
+			  struct lm3509_bl *data,
+			  const struct backlight_ops *ops,
+			  const struct lm3509_bl_led_data *led_data)
+
+{
+	struct backlight_device *bd;
+	struct backlight_properties props;
+	const char *label = led_data->label;
+	char name[64];
+
+	memset(&props, 0, sizeof(props));
+	props.type = BACKLIGHT_RAW;
+	props.brightness = led_data->brightness;
+	props.max_brightness = led_data->max_brightness;
+	props.scale = BACKLIGHT_SCALE_NON_LINEAR;
+
+	if (!label) {
+		snprintf(name, sizeof(name), "lm3509-%s-%s", dev_name(dev),
+			 name_suffix);
+		label = name;
+	}
+
+	bd = devm_backlight_device_register(dev, label, dev, data, ops, &props);
+	if (bd)
+		backlight_update_status(bd);
+
+	return bd;
+}
+
+static const struct regmap_config lm3509_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = REG_MAX,
+};
+
+static int lm3509_parse_led_sources(struct device_node *node,
+				    int default_led_sources)
+{
+	u32 sources[LM3509_NUM_SINKS];
+	int ret, num_sources, i;
+
+	num_sources = of_property_count_u32_elems(node, "led-sources");
+	if (num_sources < 0)
+		return default_led_sources;
+	else if (num_sources > ARRAY_SIZE(sources))
+		return -EINVAL;
+
+	ret = of_property_read_u32_array(node, "led-sources", sources,
+					 num_sources);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < num_sources; i++) {
+		if (sources[i] >= LM3509_NUM_SINKS)
+			return -EINVAL;
+
+		ret |= BIT(sources[i]);
+	}
+
+	return ret;
+}
+
+static int lm3509_parse_dt_node(struct device *dev,
+				struct lm3509_bl_led_data *led_data)
+{
+	struct device_node *child;
+	int seen_led_sources = 0;
+
+	for_each_child_of_node(dev->of_node, child) {
+		struct lm3509_bl_led_data *ld;
+		int ret;
+		u32 reg;
+		int valid_led_sources;
+
+		ret = of_property_read_u32(child, "reg", &reg);
+		if (ret < 0)
+			return ret;
+		if (reg >= LM3509_NUM_SINKS)
+			return -EINVAL;
+		ld = &led_data[reg];
+
+		ld->led_sources = lm3509_parse_led_sources(child, BIT(reg));
+		if (ld->led_sources < 0)
+			return ld->led_sources;
+
+		if (reg == 0)
+			valid_led_sources = BIT(LM3509_SINK_MAIN) |
+					    BIT(LM3509_SINK_SUB);
+		else
+			valid_led_sources = BIT(LM3509_SINK_SUB);
+
+		if (ld->led_sources != (ld->led_sources & valid_led_sources))
+			return -EINVAL;
+
+		if (seen_led_sources & ld->led_sources)
+			return -EINVAL;
+
+		seen_led_sources |= ld->led_sources;
+
+		ld->label = NULL;
+		of_property_read_string(child, "label", &ld->label);
+
+		ld->max_brightness = LM3509_MAX_BRIGHTNESS;
+		of_property_read_u32(child, "max-brightness",
+				     &ld->max_brightness);
+		ld->max_brightness =
+			min_t(u32, ld->max_brightness, LM3509_MAX_BRIGHTNESS);
+
+		ld->brightness = LM3509_DEF_BRIGHTNESS;
+		of_property_read_u32(child, "default-brightness",
+				     &ld->brightness);
+		ld->brightness = min_t(u32, ld->brightness, ld->max_brightness);
+	}
+
+	return 0;
+}
+
+static int lm3509_probe(struct i2c_client *client)
+{
+	struct lm3509_bl *data;
+	struct device *dev = &client->dev;
+	int ret;
+	bool oled_mode = false;
+	unsigned int reg_gp_val = 0;
+	struct lm3509_bl_led_data led_data[LM3509_NUM_SINKS];
+	u32 rate_of_change = 0;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(dev, "i2c functionality check failed\n");
+		return -EOPNOTSUPP;
+	}
+
+	data = devm_kzalloc(dev, sizeof(struct lm3509_bl), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->regmap = devm_regmap_init_i2c(client, &lm3509_regmap);
+	if (IS_ERR(data->regmap))
+		return PTR_ERR(data->regmap);
+	i2c_set_clientdata(client, data);
+
+	data->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(data->reset_gpio))
+		return dev_err_probe(dev, PTR_ERR(data->reset_gpio),
+				     "Failed to get 'reset' gpio\n");
+
+	lm3509_reset(data);
+
+	memset(led_data, 0, sizeof(led_data));
+	ret = lm3509_parse_dt_node(dev, led_data);
+	if (ret)
+		return ret;
+
+	oled_mode = of_property_read_bool(dev->of_node, "ti,oled-mode");
+
+	if (!of_property_read_u32(dev->of_node,
+				  "ti,brightness-rate-of-change-us",
+				  &rate_of_change)) {
+		switch (rate_of_change) {
+		case 51:
+			reg_gp_val = 0;
+			break;
+		case 13000:
+			reg_gp_val = BIT(REG_GP_RMP1_BIT);
+			break;
+		case 26000:
+			reg_gp_val = BIT(REG_GP_RMP0_BIT);
+			break;
+		case 52000:
+			reg_gp_val = BIT(REG_GP_RMP0_BIT) |
+				     BIT(REG_GP_RMP1_BIT);
+			break;
+		default:
+			dev_warn(dev, "invalid rate of change %u\n",
+				 rate_of_change);
+			break;
+		}
+	}
+
+	if (led_data[0].led_sources ==
+	    (BIT(LM3509_SINK_MAIN) | BIT(LM3509_SINK_SUB)))
+		reg_gp_val |= BIT(REG_GP_UNI_BIT);
+	if (oled_mode)
+		reg_gp_val |= BIT(REG_GP_OLED_BIT);
+
+	ret = regmap_write(data->regmap, REG_GP, reg_gp_val);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "failed to write register\n");
+
+	if (led_data[0].led_sources) {
+		data->bl_main = lm3509_backlight_register(
+			dev, "main", data, &lm3509_main_ops, &led_data[0]);
+		if (IS_ERR(data->bl_main)) {
+			return dev_err_probe(
+				dev, PTR_ERR(data->bl_main),
+				"failed to register main backlight\n");
+		}
+	}
+
+	if (led_data[1].led_sources) {
+		data->bl_sub = lm3509_backlight_register(
+			dev, "sub", data, &lm3509_sub_ops, &led_data[1]);
+		if (IS_ERR(data->bl_sub)) {
+			return dev_err_probe(
+				dev, PTR_ERR(data->bl_sub),
+				"failed to register secondary backlight\n");
+		}
+	}
+
+	return 0;
+}
+
+static void lm3509_remove(struct i2c_client *client)
+{
+	struct lm3509_bl *data = i2c_get_clientdata(client);
+
+	regmap_write(data->regmap, REG_GP, 0x00);
+}
+
+static const struct i2c_device_id lm3509_id[] = { { LM3509_NAME, 0 }, {} };
+
+MODULE_DEVICE_TABLE(i2c, lm3509_id);
+
+static const struct of_device_id lm3509_match_table[] = {
+	{
+		.compatible = "ti,lm3509",
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, lm3509_match_table);
+
+static struct i2c_driver lm3509_i2c_driver = {
+	.driver = {
+		.name = LM3509_NAME,
+		.of_match_table = lm3509_match_table,
+	},
+	.probe = lm3509_probe,
+	.remove = lm3509_remove,
+	.id_table = lm3509_id,
+};
+
+module_i2c_driver(lm3509_i2c_driver);
+
+MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3509");
+MODULE_AUTHOR("Patrick Gansterer <paroga@paroga.com>");
+MODULE_LICENSE("GPL");
-- 
2.44.0


^ permalink raw reply related

* Re: [PATCH v5 1/7] iio: accel: adxl345: Make data_range obsolete
From: Jonathan Cameron @ 2024-03-30 15:18 UTC (permalink / raw)
  To: Lothar Rubusch
  Cc: lars, Michael.Hennerich, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, linux-iio, devicetree, linux-kernel, eraretuya
In-Reply-To: <CAFXKEHaPcbRMVJTWW0Atg37jqb97JBdPoSmm3gAZEO1Q=SZm9w@mail.gmail.com>

On Fri, 29 Mar 2024 01:03:29 +0100
Lothar Rubusch <l.rubusch@gmail.com> wrote:

> On Thu, Mar 28, 2024 at 2:37 PM Jonathan Cameron <jic23@kernel.org> wrote:
> >
> > On Wed, 27 Mar 2024 22:03:14 +0000
> > Lothar Rubusch <l.rubusch@gmail.com> wrote:
> >  
> > > Replace write() data_format by regmap_update_bits(), because bus specific
> > > pre-configuration may have happened before on the same register. For
> > > further updates to the data_format register then bus pre-configuration
> > > needs to be masked out.
> > >
> > > Remove the data_range field from the struct adxl345_data, because it is
> > > not used anymore.
> > >
> > > Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
> > > ---
> > >  drivers/iio/accel/adxl345_core.c | 18 ++++++++++++------
> > >  1 file changed, 12 insertions(+), 6 deletions(-)
> > >
> > > diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c
> > > index 8bd30a23e..35df5e372 100644
> > > --- a/drivers/iio/accel/adxl345_core.c
> > > +++ b/drivers/iio/accel/adxl345_core.c
> > > @@ -37,7 +37,15 @@
> > >  #define ADXL345_POWER_CTL_MEASURE    BIT(3)
> > >  #define ADXL345_POWER_CTL_STANDBY    0x00
> > >
> > > +#define ADXL345_DATA_FORMAT_RANGE    GENMASK(1, 0) /* Set the g range */
> > > +#define ADXL345_DATA_FORMAT_JUSTIFY  BIT(2) /* Left-justified (MSB) mode */
> > >  #define ADXL345_DATA_FORMAT_FULL_RES BIT(3) /* Up to 13-bits resolution */
> > > +#define ADXL345_DATA_FORMAT_SELF_TEST        BIT(7) /* Enable a self test */
> > > +#define ADXL345_DATA_FORMAT_MSK              (ADXL345_DATA_FORMAT_RANGE | \
> > > +                                      ADXL345_DATA_FORMAT_JUSTIFY |  \
> > > +                                      ADXL345_DATA_FORMAT_FULL_RES | \
> > > +                                      ADXL345_DATA_FORMAT_SELF_TEST)  
> > This needs renaming.  It's not a mask of everything in the register, or
> > even just of everything related to format.
> >
> > Actually I'd just not have this definition.  Use the build up value
> > from all the submasks at the call site.  Then we are just making it clear
> > only a subset of fields are being cleared.
> >  
> I understand this solution was not very useful. I'm not sure, I
> understood you correctly. Please have a look into v6 if this matches
> your comment.
> Now, I remove the mask, instead I use a local variable in core's
> probe() for the update mask. I added a comment. Nevertheless, I keep
> the used flags for FORMAT_DATA. Does this go into the direction of
> using the build up value from the submasks at the call site?
> 
The new code looks good to me.  A local variable doesn't carry the
same implication of global applicability as the define did.
Thanks,

J
> > Jonathan
> >  
> > > +
> > >  #define ADXL345_DATA_FORMAT_2G               0
> > >  #define ADXL345_DATA_FORMAT_4G               1
> > >  #define ADXL345_DATA_FORMAT_8G               2
> > > @@ -48,7 +56,6 @@
> > >  struct adxl345_data {
> > >       const struct adxl345_chip_info *info;
> > >       struct regmap *regmap;
> > > -     u8 data_range;
> > >  };
> > >
> > >  #define ADXL345_CHANNEL(index, axis) {                                       \
> > > @@ -218,15 +225,14 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap)
> > >
> > >       data = iio_priv(indio_dev);
> > >       data->regmap = regmap;
> > > -     /* Enable full-resolution mode */
> > > -     data->data_range = ADXL345_DATA_FORMAT_FULL_RES;
> > >       data->info = device_get_match_data(dev);
> > >       if (!data->info)
> > >               return -ENODEV;
> > >
> > > -     ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT,
> > > -                        data->data_range);
> > > -     if (ret < 0)
> > > +     /* Enable full-resolution mode */
> > > +     ret = regmap_update_bits(regmap, ADXL345_REG_DATA_FORMAT,
> > > +                              ADXL345_DATA_FORMAT_MSK, ADXL345_DATA_FORMAT_FULL_RES);
> > > +     if (ret)
> > >               return dev_err_probe(dev, ret, "Failed to set data range\n");
> > >
> > >       indio_dev->name = data->info->name;  
> >  


^ permalink raw reply

* [PATCH v5 1/2] dt-bindings: backlight: Add Texas Instruments LM3509
From: Patrick Gansterer @ 2024-03-30 14:59 UTC (permalink / raw)
  To: dri-devel, linux-leds, devicetree, linux-kernel, linux-fbdev
  Cc: Patrick Gansterer, Lee Jones, Daniel Thompson, Jingoo Han,
	Pavel Machek, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Helge Deller, Sam Ravnborg, Krzysztof Kozlowski
In-Reply-To: <20240330145931.729116-1-paroga@paroga.com>

Add Device Tree bindings for Texas Instruments LM3509 - a
High Efficiency Boost for White LED's and/or OLED Displays

Signed-off-by: Patrick Gansterer <paroga@paroga.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Reviewed-by: Daniel Thompson <daniel.thompson@linaro.org>
---
 .../bindings/leds/backlight/ti,lm3509.yaml    | 139 ++++++++++++++++++
 1 file changed, 139 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/backlight/ti,lm3509.yaml

diff --git a/Documentation/devicetree/bindings/leds/backlight/ti,lm3509.yaml b/Documentation/devicetree/bindings/leds/backlight/ti,lm3509.yaml
new file mode 100644
index 000000000000..b67f67648852
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/backlight/ti,lm3509.yaml
@@ -0,0 +1,139 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/backlight/ti,lm3509.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TI LM3509 High Efficiency Boost for White LED's and/or OLED Displays
+
+maintainers:
+  - Patrick Gansterer <paroga@paroga.com>
+
+description:
+  The LM3509 current mode boost converter offers two separate outputs.
+  https://www.ti.com/product/LM3509
+
+properties:
+  compatible:
+    const: ti,lm3509
+
+  reg:
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  reset-gpios:
+    maxItems: 1
+
+  ti,brightness-rate-of-change-us:
+    description: Brightness Rate of Change in microseconds.
+    enum: [51, 13000, 26000, 52000]
+
+  ti,oled-mode:
+    description: Enable OLED mode.
+    type: boolean
+
+patternProperties:
+  "^led@[01]$":
+    type: object
+    description: Properties for a string of connected LEDs.
+
+    allOf:
+      - $ref: common.yaml#
+
+    properties:
+      reg:
+        description:
+          The control register that is used to program the two current sinks.
+          The LM3509 has two registers (BMAIN and BSUB) and are represented
+          as 0 or 1 in this property. The two current sinks can be controlled
+          independently with both registers, or register BMAIN can be
+          configured to control both sinks with the led-sources property.
+        minimum: 0
+        maximum: 1
+
+      label: true
+
+      led-sources:
+        allOf:
+          - minItems: 1
+            maxItems: 2
+            items:
+              minimum: 0
+              maximum: 1
+
+      default-brightness:
+        minimum: 0
+        maximum: 31
+        default: 18
+
+      max-brightness:
+        minimum: 0
+        maximum: 31
+        default: 31
+
+    required:
+      - reg
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        backlight@36 {
+            compatible = "ti,lm3509";
+            reg = <0x36>;
+            reset-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>;
+
+            ti,oled-mode;
+            ti,brightness-rate-of-change-us = <52000>;
+
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            led@0 {
+                reg = <0>;
+                led-sources = <0 1>;
+                label = "lcd-backlight";
+                default-brightness = <12>;
+                max-brightness = <31>;
+            };
+        };
+    };
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        backlight@36 {
+            compatible = "ti,lm3509";
+            reg = <0x36>;
+
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            led@0 {
+                reg = <0>;
+                default-brightness = <12>;
+            };
+
+            led@1 {
+                reg = <1>;
+                default-brightness = <15>;
+            };
+        };
+    };
-- 
2.44.0


^ permalink raw reply related

* Re: [PATCH 0/2] arm64: dts: fsl-lx2162a-som: add description for rtc
From: Shawn Guo @ 2024-03-30 15:07 UTC (permalink / raw)
  To: Josua Mayer
  Cc: Shawn Guo, Li Yang, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, linux-arm-kernel, devicetree, linux-kernel
In-Reply-To: <20240312-lx2162-rtc-v1-0-1f4cd431b1cf@solid-run.com>

On Tue, Mar 12, 2024 at 08:56:53PM +0100, Josua Mayer wrote:
> Josua Mayer (2):
>       arm64: dts: fsl-lx2162a-som: add description for rtc
>       arm64: dts: fsl-lx2162a-clearfog: add alias for i2c bus iic6

Applied both, thanks!


^ permalink raw reply

* [PATCH v2 3/3] drm: panel: Add LG sw43408 panel driver
From: Dmitry Baryshkov @ 2024-03-30 15:00 UTC (permalink / raw)
  To: Sumit Semwal, Caleb Connolly, Neil Armstrong, Jessica Zhang,
	Sam Ravnborg, David Airlie, Daniel Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: dri-devel, devicetree, linux-kernel, linux-arm-msm, Vinod Koul,
	Caleb Connolly
In-Reply-To: <20240330-lg-sw43408-panel-v2-0-293a58717b38@linaro.org>

From: Sumit Semwal <sumit.semwal@linaro.org>

LG SW43408 is 1080x2160, 4-lane MIPI-DSI panel, used in some Pixel3
phones.

Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
[vinod: Add DSC support]
Signed-off-by: Vinod Koul <vkoul@kernel.org>
[caleb: cleanup and support turning off the panel]
Signed-off-by: Caleb Connolly <caleb@connolly.tech>
[DB: partially rewrote the driver and fixed DSC programming]
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 MAINTAINERS                              |   8 +
 drivers/gpu/drm/panel/Kconfig            |  11 ++
 drivers/gpu/drm/panel/Makefile           |   1 +
 drivers/gpu/drm/panel/panel-lg-sw43408.c | 321 +++++++++++++++++++++++++++++++
 4 files changed, 341 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 4b511a55101c..f4cf7ee97376 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6755,6 +6755,14 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/display/panel/jadard,jd9365da-h3.yaml
 F:	drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c
 
+DRM DRIVER FOR LG SW43408 PANELS
+M:	Sumit Semwal <sumit.semwal@linaro.org>
+M:	Caleb Connolly <caleb.connolly@linaro.org>
+S:	Maintained
+T:	git git://anongit.freedesktop.org/drm/drm-misc
+F:	Documentation/devicetree/bindings/display/panel/lg,sw43408.yaml
+F:	drivers/gpu/drm/panel/panel-lg-sw43408.c
+
 DRM DRIVER FOR LOGICVC DISPLAY CONTROLLER
 M:	Paul Kocialkowski <paul.kocialkowski@bootlin.com>
 S:	Supported
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index d037b3b8b999..f94c702735cb 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -335,6 +335,17 @@ config DRM_PANEL_LG_LG4573
 	  Say Y here if you want to enable support for LG4573 RGB panel.
 	  To compile this driver as a module, choose M here.
 
+config DRM_PANEL_LG_SW43408
+	tristate "LG SW43408 panel"
+	depends on OF
+	depends on DRM_MIPI_DSI
+	depends on BACKLIGHT_CLASS_DEVICE
+	help
+	  Say Y here if you want to enable support for LG sw43408 panel.
+	  The panel has a 1080x2160 resolution and uses
+	  24 bit RGB per pixel. It provides a MIPI DSI interface to
+	  the host and has a built-in LED backlight.
+
 config DRM_PANEL_MAGNACHIP_D53E6EA8966
 	tristate "Magnachip D53E6EA8966 DSI panel"
 	depends on OF && SPI
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index f156d7fa0bcc..a75687d13caf 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += panel-leadtek-ltk050h3146w.o
 obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
 obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
 obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
+obj-$(CONFIG_DRM_PANEL_LG_SW43408) += panel-lg-sw43408.o
 obj-$(CONFIG_DRM_PANEL_MAGNACHIP_D53E6EA8966) += panel-magnachip-d53e6ea8966.o
 obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o
 obj-$(CONFIG_DRM_PANEL_NEWVISION_NV3051D) += panel-newvision-nv3051d.o
diff --git a/drivers/gpu/drm/panel/panel-lg-sw43408.c b/drivers/gpu/drm/panel/panel-lg-sw43408.c
new file mode 100644
index 000000000000..6c244b9642f1
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-lg-sw43408.c
@@ -0,0 +1,321 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-2024 Linaro Ltd
+ * Author: Sumit Semwal <sumit.semwal@linaro.org>
+ *	 Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/display/drm_dsc.h>
+#include <drm/display/drm_dsc_helper.h>
+
+#define NUM_SUPPLIES 2
+
+struct sw43408_panel {
+	struct drm_panel base;
+	struct mipi_dsi_device *link;
+
+	const struct drm_display_mode *mode;
+
+	struct regulator_bulk_data supplies[NUM_SUPPLIES];
+
+	struct gpio_desc *reset_gpio;
+
+	struct drm_dsc_config dsc;
+};
+
+static inline struct sw43408_panel *to_panel_info(struct drm_panel *panel)
+{
+	return container_of(panel, struct sw43408_panel, base);
+}
+
+static int sw43408_unprepare(struct drm_panel *panel)
+{
+	struct sw43408_panel *ctx = to_panel_info(panel);
+	int ret;
+
+	ret = mipi_dsi_dcs_set_display_off(ctx->link);
+	if (ret < 0)
+		dev_err(panel->dev, "set_display_off cmd failed ret = %d\n", ret);
+
+	ret = mipi_dsi_dcs_enter_sleep_mode(ctx->link);
+	if (ret < 0)
+		dev_err(panel->dev, "enter_sleep cmd failed ret = %d\n", ret);
+
+	msleep(100);
+
+	gpiod_set_value(ctx->reset_gpio, 1);
+
+	return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+}
+
+static int sw43408_program(struct drm_panel *panel)
+{
+	struct sw43408_panel *ctx = to_panel_info(panel);
+	struct drm_dsc_picture_parameter_set pps;
+	/* Note; this uses a non-standard argument format */
+	u8 dsc_en[] = { 0x11 };
+
+	mipi_dsi_dcs_write_seq(ctx->link, MIPI_DCS_SET_GAMMA_CURVE, 0x02);
+
+	mipi_dsi_dcs_set_tear_on(ctx->link, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
+
+	mipi_dsi_dcs_write_seq(ctx->link, 0x53, 0x0c, 0x30);
+	mipi_dsi_dcs_write_seq(ctx->link, 0x55, 0x00, 0x70, 0xdf, 0x00, 0x70, 0xdf);
+	mipi_dsi_dcs_write_seq(ctx->link, 0xf7, 0x01, 0x49, 0x0c);
+
+	mipi_dsi_dcs_exit_sleep_mode(ctx->link);
+
+	msleep(135);
+
+	mipi_dsi_compression_mode_raw(ctx->link, dsc_en, sizeof(dsc_en));
+
+	mipi_dsi_dcs_write_seq(ctx->link, 0xb0, 0xac);
+	mipi_dsi_dcs_write_seq(ctx->link, 0xe5,
+			       0x00, 0x3a, 0x00, 0x3a, 0x00, 0x0e, 0x10);
+	mipi_dsi_dcs_write_seq(ctx->link, 0xb5,
+			       0x75, 0x60, 0x2d, 0x5d, 0x80, 0x00, 0x0a, 0x0b,
+			       0x00, 0x05, 0x0b, 0x00, 0x80, 0x0d, 0x0e, 0x40,
+			       0x00, 0x0c, 0x00, 0x16, 0x00, 0xb8, 0x00, 0x80,
+			       0x0d, 0x0e, 0x40, 0x00, 0x0c, 0x00, 0x16, 0x00,
+			       0xb8, 0x00, 0x81, 0x00, 0x03, 0x03, 0x03, 0x01,
+			       0x01);
+	msleep(85);
+	mipi_dsi_dcs_write_seq(ctx->link, 0xcd,
+			       0x00, 0x00, 0x00, 0x19, 0x19, 0x19, 0x19, 0x19,
+			       0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+			       0x16, 0x16);
+	mipi_dsi_dcs_write_seq(ctx->link, 0xcb, 0x80, 0x5c, 0x07, 0x03, 0x28);
+	mipi_dsi_dcs_write_seq(ctx->link, 0xc0, 0x02, 0x02, 0x0f);
+	mipi_dsi_dcs_write_seq(ctx->link, 0x55, 0x04, 0x61, 0xdb, 0x04, 0x70, 0xdb);
+	mipi_dsi_dcs_write_seq(ctx->link, 0xb0, 0xca);
+
+	mipi_dsi_dcs_set_display_on(ctx->link);
+
+	msleep(50);
+
+	ctx->link->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+	drm_dsc_pps_payload_pack(&pps, ctx->link->dsc);
+	mipi_dsi_picture_parameter_set(ctx->link, &pps);
+
+	ctx->link->mode_flags |= MIPI_DSI_MODE_LPM;
+
+	return 0;
+}
+
+static int sw43408_prepare(struct drm_panel *panel)
+{
+	struct sw43408_panel *ctx = to_panel_info(panel);
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+	if (ret < 0)
+		return ret;
+
+	usleep_range(5000, 6000);
+
+	gpiod_set_value(ctx->reset_gpio, 0);
+	usleep_range(9000, 10000);
+	gpiod_set_value(ctx->reset_gpio, 1);
+	usleep_range(1000, 2000);
+	gpiod_set_value(ctx->reset_gpio, 0);
+	usleep_range(9000, 10000);
+
+	ret = sw43408_program(panel);
+	if (ret)
+		goto poweroff;
+
+	return 0;
+
+poweroff:
+	gpiod_set_value(ctx->reset_gpio, 1);
+	regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+	return ret;
+}
+
+static int sw43408_get_modes(struct drm_panel *panel,
+			      struct drm_connector *connector)
+{
+	struct sw43408_panel *ctx = to_panel_info(panel);
+
+	return drm_connector_helper_get_modes_fixed(connector, ctx->mode);
+}
+
+static int sw43408_backlight_update_status(struct backlight_device *bl)
+{
+	struct mipi_dsi_device *dsi = bl_get_data(bl);
+	uint16_t brightness = backlight_get_brightness(bl);
+
+	return mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
+}
+
+const struct backlight_ops sw43408_backlight_ops = {
+	.update_status = sw43408_backlight_update_status,
+};
+
+static int sw43408_backlight_init(struct sw43408_panel *ctx)
+{
+	struct device *dev = &ctx->link->dev;
+	const struct backlight_properties props = {
+		.type = BACKLIGHT_PLATFORM,
+		.brightness = 255,
+		.max_brightness = 255,
+	};
+
+	ctx->base.backlight = devm_backlight_device_register(dev, dev_name(dev), dev,
+							ctx->link,
+							&sw43408_backlight_ops,
+							&props);
+
+	if (IS_ERR(ctx->base.backlight))
+		return dev_err_probe(dev, PTR_ERR(ctx->base.backlight),
+				     "Failed to create backlight\n");
+
+	return 0;
+}
+
+static const struct drm_panel_funcs sw43408_funcs = {
+	.unprepare = sw43408_unprepare,
+	.prepare = sw43408_prepare,
+	.get_modes = sw43408_get_modes,
+};
+
+static const struct drm_display_mode sw43408_default_mode = {
+	.clock = 152340,
+
+	.hdisplay = 1080,
+	.hsync_start = 1080 + 20,
+	.hsync_end = 1080 + 20 + 32,
+	.htotal = 1080 + 20 + 32 + 20,
+
+	.vdisplay = 2160,
+	.vsync_start = 2160 + 20,
+	.vsync_end = 2160 + 20 + 4,
+	.vtotal = 2160 + 20 + 4 + 20,
+
+	.width_mm = 62,
+	.height_mm = 124,
+
+	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static const struct of_device_id sw43408_of_match[] = {
+	{ .compatible = "lg,sw43408", .data = &sw43408_default_mode },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sw43408_of_match);
+
+static int sw43408_add(struct sw43408_panel *ctx)
+{
+	struct device *dev = &ctx->link->dev;
+	int ret;
+
+	ctx->supplies[0].supply = "vddi"; /* 1.88 V */
+	ctx->supplies[0].init_load_uA = 62000;
+	ctx->supplies[1].supply = "vpnl"; /* 3.0 V */
+	ctx->supplies[1].init_load_uA = 857000;
+
+	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
+				      ctx->supplies);
+	if (ret < 0)
+		return ret;
+
+	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(ctx->reset_gpio)) {
+		dev_err(dev, "cannot get reset gpio %ld\n",
+			      PTR_ERR(ctx->reset_gpio));
+		return PTR_ERR(ctx->reset_gpio);
+	}
+
+	ret = sw43408_backlight_init(ctx);
+	if (ret < 0)
+		return ret;
+
+	ctx->base.prepare_prev_first = true;
+
+	drm_panel_init(&ctx->base, dev, &sw43408_funcs, DRM_MODE_CONNECTOR_DSI);
+
+	drm_panel_add(&ctx->base);
+	return ret;
+}
+
+static int sw43408_probe(struct mipi_dsi_device *dsi)
+{
+	struct sw43408_panel *ctx;
+	int ret;
+
+	ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->mode = of_device_get_match_data(&dsi->dev);
+	dsi->mode_flags = MIPI_DSI_MODE_LPM;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->lanes = 4;
+
+	ctx->link = dsi;
+	mipi_dsi_set_drvdata(dsi, ctx);
+
+	ret = sw43408_add(ctx);
+	if (ret < 0)
+		return ret;
+
+	/* The panel is DSC panel only, set the dsc params */
+	ctx->dsc.dsc_version_major = 0x1;
+	ctx->dsc.dsc_version_minor = 0x1;
+
+	/* slice_count * slice_width == width */
+	ctx->dsc.slice_height = 16;
+	ctx->dsc.slice_width = 540;
+	ctx->dsc.slice_count = 2;
+	ctx->dsc.bits_per_component = 8;
+	ctx->dsc.bits_per_pixel = 8 << 4;
+	ctx->dsc.block_pred_enable = true;
+
+	dsi->dsc = &ctx->dsc;
+
+	return mipi_dsi_attach(dsi);
+}
+
+static void sw43408_remove(struct mipi_dsi_device *dsi)
+{
+	struct sw43408_panel *ctx = mipi_dsi_get_drvdata(dsi);
+	int ret;
+
+	ret = sw43408_unprepare(&ctx->base);
+	if (ret < 0)
+		dev_err(&dsi->dev, "failed to unprepare panel: %d\n",
+			      ret);
+
+	ret = mipi_dsi_detach(dsi);
+	if (ret < 0)
+		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
+
+	drm_panel_remove(&ctx->base);
+}
+
+static struct mipi_dsi_driver sw43408_driver = {
+	.driver = {
+		.name = "panel-lg-sw43408",
+		.of_match_table = sw43408_of_match,
+	},
+	.probe = sw43408_probe,
+	.remove = sw43408_remove,
+};
+module_mipi_dsi_driver(sw43408_driver);
+
+MODULE_AUTHOR("Sumit Semwal <sumit.semwal@linaro.org>");
+MODULE_DESCRIPTION("LG SW436408 MIPI-DSI LED panel");
+MODULE_LICENSE("GPL");

-- 
2.39.2


^ permalink raw reply related

* [PATCH v2 2/3] drm/mipi-dsi: add mipi_dsi_compression_mode_raw()
From: Dmitry Baryshkov @ 2024-03-30 15:00 UTC (permalink / raw)
  To: Sumit Semwal, Caleb Connolly, Neil Armstrong, Jessica Zhang,
	Sam Ravnborg, David Airlie, Daniel Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: dri-devel, devicetree, linux-kernel, linux-arm-msm
In-Reply-To: <20240330-lg-sw43408-panel-v2-0-293a58717b38@linaro.org>

The LG SW43408 panel requires sending non-standard data as a part of the
MIPI_DSI_COMPRESSION_MODE packet. Rather than hacking existing
mipi_dsi_compression_mode() add mipi_dsi_compression_mode_raw(), which
accepts raw data buffer and length.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/drm_mipi_dsi.c | 34 ++++++++++++++++++++++++++--------
 include/drm/drm_mipi_dsi.h     |  1 +
 2 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index ef6e416522f8..f340d1e0a9a5 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -645,29 +645,47 @@ int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
 EXPORT_SYMBOL(mipi_dsi_set_maximum_return_packet_size);
 
 /**
- * mipi_dsi_compression_mode() - enable/disable DSC on the peripheral
+ * mipi_dsi_compression_mode_raw() - control DSC on the peripheral
  * @dsi: DSI peripheral device
- * @enable: Whether to enable or disable the DSC
+ * @data: data to be sent to the device
+ * @len: size of the data buffer
  *
- * Enable or disable Display Stream Compression on the peripheral using the
+ * Control the Display Stream Compression on the peripheral using the
  * default Picture Parameter Set and VESA DSC 1.1 algorithm.
  *
  * Return: 0 on success or a negative error code on failure.
  */
-ssize_t mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable)
+ssize_t mipi_dsi_compression_mode_raw(struct mipi_dsi_device *dsi, void *data, size_t len)
 {
-	/* Note: Needs updating for non-default PPS or algorithm */
-	u8 tx[2] = { enable << 0, 0 };
 	struct mipi_dsi_msg msg = {
 		.channel = dsi->channel,
 		.type = MIPI_DSI_COMPRESSION_MODE,
-		.tx_len = sizeof(tx),
-		.tx_buf = tx,
+		.tx_len = len,
+		.tx_buf = data,
 	};
 	int ret = mipi_dsi_device_transfer(dsi, &msg);
 
 	return (ret < 0) ? ret : 0;
 }
+EXPORT_SYMBOL(mipi_dsi_compression_mode_raw);
+
+/**
+ * mipi_dsi_compression_mode() - enable/disable DSC on the peripheral
+ * @dsi: DSI peripheral device
+ * @enable: Whether to enable or disable the DSC
+ *
+ * Enable or disable Display Stream Compression on the peripheral using the
+ * default Picture Parameter Set and VESA DSC 1.1 algorithm.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+ssize_t mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable)
+{
+	/* Note: Needs updating for non-default PPS or algorithm */
+	u8 tx[2] = { enable << 0, 0 };
+
+	return mipi_dsi_compression_mode_raw(dsi, tx, sizeof(tx));
+}
 EXPORT_SYMBOL(mipi_dsi_compression_mode);
 
 /**
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index c0aec0d4d664..321d2b019687 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -242,6 +242,7 @@ int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi);
 int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
 					    u16 value);
 ssize_t mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable);
+ssize_t mipi_dsi_compression_mode_raw(struct mipi_dsi_device *dsi, void *data, size_t len);
 ssize_t mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi,
 				       const struct drm_dsc_picture_parameter_set *pps);
 

-- 
2.39.2


^ permalink raw reply related

* [PATCH v2 1/3] dt-bindings: panel: Add LG SW43408 MIPI-DSI panel
From: Dmitry Baryshkov @ 2024-03-30 15:00 UTC (permalink / raw)
  To: Sumit Semwal, Caleb Connolly, Neil Armstrong, Jessica Zhang,
	Sam Ravnborg, David Airlie, Daniel Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: dri-devel, devicetree, linux-kernel, linux-arm-msm, Vinod Koul,
	Caleb Connolly
In-Reply-To: <20240330-lg-sw43408-panel-v2-0-293a58717b38@linaro.org>

From: Sumit Semwal <sumit.semwal@linaro.org>

LG SW43408 is 1080x2160, 4-lane MIPI-DSI panel present on Google Pixel 3
phones.

Signed-off-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
[caleb: convert to yaml]
Signed-off-by: Caleb Connolly <caleb@connolly.tech>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 .../bindings/display/panel/lg,sw43408.yaml         | 62 ++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/panel/lg,sw43408.yaml b/Documentation/devicetree/bindings/display/panel/lg,sw43408.yaml
new file mode 100644
index 000000000000..1e08648f5bc7
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/lg,sw43408.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/lg,sw43408.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LG SW43408 1080x2160 DSI panel
+
+maintainers:
+  - Caleb Connolly <caleb.connolly@linaro.org>
+
+description:
+  This panel is used on the Pixel 3, it is a 60hz OLED panel which
+  required DSC (Display Stream Compression) and has rounded corners.
+
+allOf:
+  - $ref: panel-common.yaml#
+
+properties:
+  compatible:
+    items:
+      - const: lg,sw43408
+
+  reg: true
+  port: true
+  vddi-supply: true
+  vpnl-supply: true
+  reset-gpios: true
+
+required:
+  - compatible
+  - vddi-supply
+  - vpnl-supply
+  - reset-gpios
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    dsi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        panel@0 {
+            compatible = "lg,sw43408";
+            reg = <0>;
+
+            vddi-supply = <&vreg_l14a_1p88>;
+            vpnl-supply = <&vreg_l28a_3p0>;
+
+            reset-gpios = <&tlmm 6 GPIO_ACTIVE_LOW>;
+
+            port {
+                endpoint {
+                    remote-endpoint = <&mdss_dsi0_out>;
+                };
+            };
+        };
+    };
+...

-- 
2.39.2


^ permalink raw reply related

* [PATCH v2 0/3] drm/panel: add support for LG SW43408 panel
From: Dmitry Baryshkov @ 2024-03-30 15:00 UTC (permalink / raw)
  To: Sumit Semwal, Caleb Connolly, Neil Armstrong, Jessica Zhang,
	Sam Ravnborg, David Airlie, Daniel Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: dri-devel, devicetree, linux-kernel, linux-arm-msm, Vinod Koul,
	Caleb Connolly

The LG SW43408 panel is used on Google Pixel3 devices. For a long time
we could not submit the driver, as the panel was not coming up from the
reset. The panel seems to be picky about some of the delays during init
and it also uses non-standard payload for MIPI_DSI_COMPRESSION_MODE.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
Changes in v2:
- Removed formatting char from schema (Krzysztof)
- Moved additionalProperties after required (Krzysztof)
- Added example to the schema (Krzysztof)
- Removed obsolete comment in the commit message (Marijn)
- Moved DSC params to the panel struct (Marijn)
- Changed dsc_en to be an array (Marijn)
- Added comment regiarding slice_width and slice_count (Marijn)
- Link to v1: https://lore.kernel.org/r/20240330-lg-sw43408-panel-v1-0-f5580fc9f2da@linaro.org

---
Dmitry Baryshkov (1):
      drm/mipi-dsi: add mipi_dsi_compression_mode_raw()

Sumit Semwal (2):
      dt-bindings: panel: Add LG SW43408 MIPI-DSI panel
      drm: panel: Add LG sw43408 panel driver

 .../bindings/display/panel/lg,sw43408.yaml         |  62 ++++
 MAINTAINERS                                        |   8 +
 drivers/gpu/drm/drm_mipi_dsi.c                     |  34 ++-
 drivers/gpu/drm/panel/Kconfig                      |  11 +
 drivers/gpu/drm/panel/Makefile                     |   1 +
 drivers/gpu/drm/panel/panel-lg-sw43408.c           | 321 +++++++++++++++++++++
 include/drm/drm_mipi_dsi.h                         |   1 +
 7 files changed, 430 insertions(+), 8 deletions(-)
---
base-commit: 13ee4a7161b6fd938aef6688ff43b163f6d83e37
change-id: 20240330-lg-sw43408-panel-b552f411c53e

Best regards,
-- 
Dmitry Baryshkov <dmitry.baryshkov@linaro.org>


^ permalink raw reply

* Re: [PATCH net-next v6 17/17] net: pse-pd: Add TI TPS23881 PSE controller driver
From: Andrew Lunn @ 2024-03-30 14:52 UTC (permalink / raw)
  To: Kory Maincent
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Jonathan Corbet, Luis Chamberlain, Russ Weight,
	Greg Kroah-Hartman, Rafael J. Wysocki, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Oleksij Rempel, Mark Brown,
	Frank Rowand, Heiner Kallweit, Russell King, Thomas Petazzoni,
	netdev, linux-kernel, linux-doc, devicetree, Dent Project
In-Reply-To: <20240329155657.7939ac4b@kmaincent-XPS-13-7390>

On Fri, Mar 29, 2024 at 03:56:57PM +0100, Kory Maincent wrote:
> On Thu, 28 Mar 2024 17:24:17 +0100
> Andrew Lunn <andrew@lunn.ch> wrote:
> 
> > > +static int tps23881_flash_fw_part(struct i2c_client *client,
> > > +				  const char *fw_name,
> > > +				  const struct tps23881_fw_conf *fw_conf)  
> > 
> > Does the device actually have flash? Or is this just downloading to
> > SRAM?
> 
> It is downloading to SRAM.

So maybe rename these functions.

	Andrew

^ permalink raw reply

* Re: [PATCH 3/3] drm: panel: Add LG sw43408 panel driver
From: Dmitry Baryshkov @ 2024-03-30 14:37 UTC (permalink / raw)
  To: Marijn Suijten
  Cc: Sumit Semwal, Caleb Connolly, Neil Armstrong, Jessica Zhang,
	Sam Ravnborg, David Airlie, Daniel Vetter, Maarten Lankhorst,
	Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, dri-devel, devicetree,
	linux-kernel, linux-arm-msm, Vinod Koul, Caleb Connolly
In-Reply-To: <554zkisebym7gbbom3657ws7kqvyidggfmcvetjm6vrnwts3gl@l53hejt72b5q>

On Sat, 30 Mar 2024 at 12:27, Marijn Suijten
<marijn.suijten@somainline.org> wrote:
>
> On 2024-03-30 05:59:30, Dmitry Baryshkov wrote:
> > From: Sumit Semwal <sumit.semwal@linaro.org>
> >
> > LG SW43408 is 1080x2160, 4-lane MIPI-DSI panel, used in some Pixel3
> > phones.
> >
> > Whatever init sequence we have for this panel isn't capable of
> > initialising it completely, toggling the reset gpio ever causes the
> > panel to die. Until this is resolved we avoid resetting the panel. The
>
> Are you sure it is avoided?  This patch seems to be toggling reset_gpio in
> sw43408_prepare()?
>
> > disable/unprepare functions only put the panel to sleep mode and
> > disable the backlight.
> >
> > Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
> > [vinod: Add DSC support]
> > Signed-off-by: Vinod Koul <vkoul@kernel.org>
> > [caleb: cleanup and support turning off the panel]
> > Signed-off-by: Caleb Connolly <caleb@connolly.tech>
> > [DB: partially rewrote the driver and fixed DSC programming]
> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > ---
> >  MAINTAINERS                              |   8 +
> >  drivers/gpu/drm/panel/Kconfig            |  11 ++
> >  drivers/gpu/drm/panel/Makefile           |   1 +
> >  drivers/gpu/drm/panel/panel-lg-sw43408.c | 322 +++++++++++++++++++++++++++++++
> >  4 files changed, 342 insertions(+)
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 4b511a55101c..f4cf7ee97376 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -6755,6 +6755,14 @@ S:     Maintained
> >  F:   Documentation/devicetree/bindings/display/panel/jadard,jd9365da-h3.yaml
> >  F:   drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c
> >
> > +DRM DRIVER FOR LG SW43408 PANELS
> > +M:   Sumit Semwal <sumit.semwal@linaro.org>
> > +M:   Caleb Connolly <caleb.connolly@linaro.org>
> > +S:   Maintained
> > +T:   git git://anongit.freedesktop.org/drm/drm-misc
> > +F:   Documentation/devicetree/bindings/display/panel/lg,sw43408.yaml
> > +F:   drivers/gpu/drm/panel/panel-lg-sw43408.c
> > +
> >  DRM DRIVER FOR LOGICVC DISPLAY CONTROLLER
> >  M:   Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> >  S:   Supported
> > diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> > index d037b3b8b999..f94c702735cb 100644
> > --- a/drivers/gpu/drm/panel/Kconfig
> > +++ b/drivers/gpu/drm/panel/Kconfig
> > @@ -335,6 +335,17 @@ config DRM_PANEL_LG_LG4573
> >         Say Y here if you want to enable support for LG4573 RGB panel.
> >         To compile this driver as a module, choose M here.
> >
> > +config DRM_PANEL_LG_SW43408
> > +     tristate "LG SW43408 panel"
> > +     depends on OF
> > +     depends on DRM_MIPI_DSI
> > +     depends on BACKLIGHT_CLASS_DEVICE
> > +     help
> > +       Say Y here if you want to enable support for LG sw43408 panel.
> > +       The panel has a 1080x2160 resolution and uses
> > +       24 bit RGB per pixel. It provides a MIPI DSI interface to
> > +       the host and has a built-in LED backlight.
> > +
> >  config DRM_PANEL_MAGNACHIP_D53E6EA8966
> >       tristate "Magnachip D53E6EA8966 DSI panel"
> >       depends on OF && SPI
> > diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> > index f156d7fa0bcc..a75687d13caf 100644
> > --- a/drivers/gpu/drm/panel/Makefile
> > +++ b/drivers/gpu/drm/panel/Makefile
> > @@ -34,6 +34,7 @@ obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += panel-leadtek-ltk050h3146w.o
> >  obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
> >  obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
> >  obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
> > +obj-$(CONFIG_DRM_PANEL_LG_SW43408) += panel-lg-sw43408.o
> >  obj-$(CONFIG_DRM_PANEL_MAGNACHIP_D53E6EA8966) += panel-magnachip-d53e6ea8966.o
> >  obj-$(CONFIG_DRM_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o
> >  obj-$(CONFIG_DRM_PANEL_NEWVISION_NV3051D) += panel-newvision-nv3051d.o
> > diff --git a/drivers/gpu/drm/panel/panel-lg-sw43408.c b/drivers/gpu/drm/panel/panel-lg-sw43408.c
> > new file mode 100644
> > index 000000000000..365d25e14d54
> > --- /dev/null
> > +++ b/drivers/gpu/drm/panel/panel-lg-sw43408.c
> > @@ -0,0 +1,322 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Copyright (C) 2019-2024 Linaro Ltd
> > + * Author: Sumit Semwal <sumit.semwal@linaro.org>
> > + *    Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > + */
> > +
> > +#include <linux/backlight.h>
> > +#include <linux/delay.h>
> > +#include <linux/gpio/consumer.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/regulator/consumer.h>
> > +
> > +#include <video/mipi_display.h>
> > +
> > +#include <drm/drm_mipi_dsi.h>
> > +#include <drm/drm_panel.h>
> > +#include <drm/drm_probe_helper.h>
> > +#include <drm/display/drm_dsc.h>
> > +#include <drm/display/drm_dsc_helper.h>
> > +
> > +#define NUM_SUPPLIES 2
> > +
> > +struct sw43408_panel {
> > +     struct drm_panel base;
> > +     struct mipi_dsi_device *link;
> > +
> > +     const struct drm_display_mode *mode;
> > +
> > +     struct regulator_bulk_data supplies[NUM_SUPPLIES];
> > +
> > +     struct gpio_desc *reset_gpio;
> > +};
> > +
> > +static inline struct sw43408_panel *to_panel_info(struct drm_panel *panel)
> > +{
> > +     return container_of(panel, struct sw43408_panel, base);
> > +}
> > +
> > +static int sw43408_unprepare(struct drm_panel *panel)
> > +{
> > +     struct sw43408_panel *ctx = to_panel_info(panel);
> > +     int ret;
> > +
> > +     ret = mipi_dsi_dcs_set_display_off(ctx->link);
> > +     if (ret < 0)
> > +             dev_err(panel->dev, "set_display_off cmd failed ret = %d\n", ret);
> > +
> > +     ret = mipi_dsi_dcs_enter_sleep_mode(ctx->link);
> > +     if (ret < 0)
> > +             dev_err(panel->dev, "enter_sleep cmd failed ret = %d\n", ret);
> > +
> > +     msleep(100);
> > +
> > +     gpiod_set_value(ctx->reset_gpio, 1);
> > +
> > +     return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> > +}
> > +
> > +static int sw43408_program(struct drm_panel *panel)
> > +{
> > +     struct sw43408_panel *ctx = to_panel_info(panel);
> > +     struct drm_dsc_picture_parameter_set pps;
> > +     u8 dsc_en = 0x11;
>
> Yeah, this is completely strange. Bit 0, 0x1, is to enable DSC which is
> normal. 0x10 however, which is bit 4, selects PPS table 2.  Do you ever set
> pps_identifier in struct drm_dsc_picture_parameter_set to 2?  Or is the table
> that you send below bogus and/or not used?  Maybe the Driver IC on the other
> end of the DSI link has a default PPS table with identifier 2 that works out of
> the box?

Note, MIPI standard also requires two bytes argument. I suspect that
LG didn't fully follow the standard here.
Basically that's the reason why I went for the _raw function instead
of adding PPS and codec arguments to the existing function.

>
> > +     mipi_dsi_dcs_write_seq(ctx->link, MIPI_DCS_SET_GAMMA_CURVE, 0x02);
> > +
> > +     mipi_dsi_dcs_set_tear_on(ctx->link, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
> > +
> > +     mipi_dsi_dcs_write_seq(ctx->link, 0x53, 0x0c, 0x30);
> > +     mipi_dsi_dcs_write_seq(ctx->link, 0x55, 0x00, 0x70, 0xdf, 0x00, 0x70, 0xdf);
> > +     mipi_dsi_dcs_write_seq(ctx->link, 0xf7, 0x01, 0x49, 0x0c);
> > +
> > +     mipi_dsi_dcs_exit_sleep_mode(ctx->link);
> > +
> > +     msleep(135);
> > +
> > +     mipi_dsi_compression_mode_raw(ctx->link, &dsc_en, 1);
>
> Even though I think we should change this function to describe the known
> bit layout of command 0x7 per the VESA DSI spec, for now replace 1 with
> sizeof(dsc_en)?

If dsc_en were an array, it would have been a proper thing. Maybe I
should change it to the array to remove confusion.

>
> > +
> > +     mipi_dsi_dcs_write_seq(ctx->link, 0xb0, 0xac);
> > +     mipi_dsi_dcs_write_seq(ctx->link, 0xe5,
> > +                            0x00, 0x3a, 0x00, 0x3a, 0x00, 0x0e, 0x10);
> > +     mipi_dsi_dcs_write_seq(ctx->link, 0xb5,
> > +                            0x75, 0x60, 0x2d, 0x5d, 0x80, 0x00, 0x0a, 0x0b,
> > +                            0x00, 0x05, 0x0b, 0x00, 0x80, 0x0d, 0x0e, 0x40,
> > +                            0x00, 0x0c, 0x00, 0x16, 0x00, 0xb8, 0x00, 0x80,
> > +                            0x0d, 0x0e, 0x40, 0x00, 0x0c, 0x00, 0x16, 0x00,
> > +                            0xb8, 0x00, 0x81, 0x00, 0x03, 0x03, 0x03, 0x01,
> > +                            0x01);
> > +     msleep(85);
> > +     mipi_dsi_dcs_write_seq(ctx->link, 0xcd,
> > +                            0x00, 0x00, 0x00, 0x19, 0x19, 0x19, 0x19, 0x19,
> > +                            0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
> > +                            0x16, 0x16);
> > +     mipi_dsi_dcs_write_seq(ctx->link, 0xcb, 0x80, 0x5c, 0x07, 0x03, 0x28);
> > +     mipi_dsi_dcs_write_seq(ctx->link, 0xc0, 0x02, 0x02, 0x0f);
> > +     mipi_dsi_dcs_write_seq(ctx->link, 0x55, 0x04, 0x61, 0xdb, 0x04, 0x70, 0xdb);
> > +     mipi_dsi_dcs_write_seq(ctx->link, 0xb0, 0xca);
> > +
> > +     mipi_dsi_dcs_set_display_on(ctx->link);
>
> Any specific reason to not have the (un)blanking sequence in the enable/disable
> callbacks and leaving display configuration in (un)prepare?

We are back to the question on when it's fine to send the commands. I
think the current agreement is to send everything in the
prepare/unprepare, because of some strange hosts.

> > +     msleep(50);
> > +
> > +     ctx->link->mode_flags &= ~MIPI_DSI_MODE_LPM;
> > +
> > +     drm_dsc_pps_payload_pack(&pps, ctx->link->dsc);
> > +     mipi_dsi_picture_parameter_set(ctx->link, &pps);
>
> I'm always surprised why this is sent _after_ turning the display on (unblanking
> it).  Wouldn't that cause unnecessary corruption?

No idea. I followed the dowsntream command sequences here. Most likely
the panel is not fully on until it receives the full frame to be
displayed.

> > +
> > +     ctx->link->mode_flags |= MIPI_DSI_MODE_LPM;
> > +
> > +     return 0;
> > +}
> > +
> > +static int sw43408_prepare(struct drm_panel *panel)
> > +{
> > +     struct sw43408_panel *ctx = to_panel_info(panel);
> > +     int ret;
> > +
> > +     ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     usleep_range(5000, 6000);
> > +
> > +     gpiod_set_value(ctx->reset_gpio, 0);
> > +     usleep_range(9000, 10000);
> > +     gpiod_set_value(ctx->reset_gpio, 1);
> > +     usleep_range(1000, 2000);
> > +     gpiod_set_value(ctx->reset_gpio, 0);
> > +     usleep_range(9000, 10000);
> > +
> > +     ret = sw43408_program(panel);
> > +     if (ret)
> > +             goto poweroff;
> > +
> > +     return 0;
> > +
> > +poweroff:
> > +     gpiod_set_value(ctx->reset_gpio, 1);
> > +     regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
> > +     return ret;
> > +}
> > +
> > +static int sw43408_get_modes(struct drm_panel *panel,
> > +                           struct drm_connector *connector)
> > +{
> > +     struct sw43408_panel *ctx = to_panel_info(panel);
> > +
> > +     return drm_connector_helper_get_modes_fixed(connector, ctx->mode);
> > +}
> > +
> > +static int sw43408_backlight_update_status(struct backlight_device *bl)
> > +{
> > +     struct mipi_dsi_device *dsi = bl_get_data(bl);
> > +     uint16_t brightness = backlight_get_brightness(bl);
> > +
> > +     return mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
> > +}
> > +
> > +const struct backlight_ops sw43408_backlight_ops = {
> > +     .update_status = sw43408_backlight_update_status,
> > +};
> > +
> > +static int sw43408_backlight_init(struct sw43408_panel *ctx)
> > +{
> > +     struct device *dev = &ctx->link->dev;
> > +     const struct backlight_properties props = {
> > +             .type = BACKLIGHT_PLATFORM,
> > +             .brightness = 255,
> > +             .max_brightness = 255,
> > +     };
> > +
> > +     ctx->base.backlight = devm_backlight_device_register(dev, dev_name(dev), dev,
> > +                                                     ctx->link,
> > +                                                     &sw43408_backlight_ops,
> > +                                                     &props);
> > +
> > +     if (IS_ERR(ctx->base.backlight))
> > +             return dev_err_probe(dev, PTR_ERR(ctx->base.backlight),
> > +                                  "Failed to create backlight\n");
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct drm_panel_funcs sw43408_funcs = {
> > +     .unprepare = sw43408_unprepare,
> > +     .prepare = sw43408_prepare,
> > +     .get_modes = sw43408_get_modes,
> > +};
> > +
> > +static const struct drm_display_mode sw43408_default_mode = {
> > +     .clock = 152340,
> > +
> > +     .hdisplay = 1080,
> > +     .hsync_start = 1080 + 20,
> > +     .hsync_end = 1080 + 20 + 32,
> > +     .htotal = 1080 + 20 + 32 + 20,
> > +
> > +     .vdisplay = 2160,
> > +     .vsync_start = 2160 + 20,
> > +     .vsync_end = 2160 + 20 + 4,
> > +     .vtotal = 2160 + 20 + 4 + 20,
> > +
> > +     .width_mm = 62,
> > +     .height_mm = 124,
> > +
> > +     .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
> > +};
> > +
> > +static const struct of_device_id sw43408_of_match[] = {
> > +     { .compatible = "lg,sw43408", .data = &sw43408_default_mode },
> > +     { /* sentinel */ }
> > +};
> > +MODULE_DEVICE_TABLE(of, sw43408_of_match);
> > +
> > +static int sw43408_add(struct sw43408_panel *ctx)
> > +{
> > +     struct device *dev = &ctx->link->dev;
> > +     int ret;
> > +
> > +     ctx->supplies[0].supply = "vddi"; /* 1.88 V */
> > +     ctx->supplies[0].init_load_uA = 62000;
> > +     ctx->supplies[1].supply = "vpnl"; /* 3.0 V */
> > +     ctx->supplies[1].init_load_uA = 857000;
> > +
> > +     ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
> > +                                   ctx->supplies);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
> > +     if (IS_ERR(ctx->reset_gpio)) {
> > +             dev_err(dev, "cannot get reset gpio %ld\n",
> > +                           PTR_ERR(ctx->reset_gpio));
> > +             return PTR_ERR(ctx->reset_gpio);
> > +     }
> > +
> > +     ret = sw43408_backlight_init(ctx);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     ctx->base.prepare_prev_first = true;
> > +
> > +     drm_panel_init(&ctx->base, dev, &sw43408_funcs, DRM_MODE_CONNECTOR_DSI);
> > +
> > +     drm_panel_add(&ctx->base);
> > +     return ret;
> > +}
> > +
> > +static int sw43408_probe(struct mipi_dsi_device *dsi)
> > +{
> > +     struct sw43408_panel *ctx;
> > +     struct drm_dsc_config *dsc;
> > +     int ret;
> > +
> > +     ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
> > +     if (!ctx)
> > +             return -ENOMEM;
> > +
> > +     ctx->mode = of_device_get_match_data(&dsi->dev);
> > +     dsi->mode_flags = MIPI_DSI_MODE_LPM;
> > +     dsi->format = MIPI_DSI_FMT_RGB888;
> > +     dsi->lanes = 4;
> > +
> > +     ctx->link = dsi;
> > +     mipi_dsi_set_drvdata(dsi, ctx);
> > +
> > +     ret = sw43408_add(ctx);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     /* The panel is DSC panel only, set the dsc params */
> > +     dsc = devm_kzalloc(&dsi->dev, sizeof(*dsc), GFP_KERNEL);
>
> We've recently decided to store struct drm_dsc_config in struct sw43408_panel
> and save on an extra allocation.
>
> > +     if (!dsc)
> > +             return -ENOMEM;
> > +
> > +     dsc->dsc_version_major = 0x1;
> > +     dsc->dsc_version_minor = 0x1;
> > +
> > +     dsc->slice_height = 16;
> > +     dsc->slice_width = 540;
> > +     dsc->slice_count = 2;
>
> Maybe incorporate with a comment that slice_count * slice_width == the width of
> the mode?

ack

>
> - Marijn
>
> > +     dsc->bits_per_component = 8;
> > +     dsc->bits_per_pixel = 8 << 4;
> > +     dsc->block_pred_enable = true;
> > +
> > +     dsi->dsc = dsc;
> > +
> > +     return mipi_dsi_attach(dsi);
> > +}
> > +
> > +static void sw43408_remove(struct mipi_dsi_device *dsi)
> > +{
> > +     struct sw43408_panel *ctx = mipi_dsi_get_drvdata(dsi);
> > +     int ret;
> > +
> > +     ret = sw43408_unprepare(&ctx->base);
> > +     if (ret < 0)
> > +             dev_err(&dsi->dev, "failed to unprepare panel: %d\n",
> > +                           ret);
> > +
> > +     ret = mipi_dsi_detach(dsi);
> > +     if (ret < 0)
> > +             dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
> > +
> > +     drm_panel_remove(&ctx->base);
> > +}
> > +
> > +static struct mipi_dsi_driver sw43408_driver = {
> > +     .driver = {
> > +             .name = "panel-lg-sw43408",
> > +             .of_match_table = sw43408_of_match,
> > +     },
> > +     .probe = sw43408_probe,
> > +     .remove = sw43408_remove,
> > +};
> > +module_mipi_dsi_driver(sw43408_driver);
> > +
> > +MODULE_AUTHOR("Sumit Semwal <sumit.semwal@linaro.org>");
> > +MODULE_DESCRIPTION("LG SW436408 MIPI-DSI LED panel");
> > +MODULE_LICENSE("GPL");
> >
> > --
> > 2.39.2
> >



-- 
With best wishes
Dmitry

^ permalink raw reply

* Re: [PATCH v7 2/2] dmaengine: Loongson1: Add Loongson-1 APB DMA driver
From: Huacai Chen @ 2024-03-30 13:59 UTC (permalink / raw)
  To: keguang.zhang
  Cc: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	linux-mips, dmaengine, devicetree, linux-kernel
In-Reply-To: <20240329-loongson1-dma-v7-2-37db58608de5@gmail.com>

Hi, Keguang,

On Fri, Mar 29, 2024 at 7:28 PM Keguang Zhang via B4 Relay
<devnull+keguang.zhang.gmail.com@kernel.org> wrote:
>
> From: Keguang Zhang <keguang.zhang@gmail.com>
>
> This patch adds APB DMA driver for Loongson-1 SoCs.
>
> Signed-off-by: Keguang Zhang <keguang.zhang@gmail.com>
> ---
> Changes in v7:
> - Change the comptible to 'loongson,ls1*-apbdma'
> - Update Kconfig and Makefile accordingly
> - Rename the file to loongson1-apb-dma.c to keep the consistency
>
> Changes in v6:
> - Implement .device_prep_dma_cyclic for Loongson1 audio driver,
> - as well as .device_pause and .device_resume.
> - Set the limitation LS1X_DMA_MAX_DESC and put all descriptors
> - into one page to save memory
> - Move dma_pool_zalloc() into ls1x_dma_alloc_desc()
> - Drop dma_slave_config structure
> - Use .remove_new instead of .remove
> - Use KBUILD_MODNAME for the driver name
> - Improve the debug information
>
> Changes in v5:
> - Add DT support
> - Use DT data instead of platform data
> - Use chan_id of struct dma_chan instead of own id
> - Use of_dma_xlate_by_chan_id() instead of ls1x_dma_filter()
> - Update the author information to my official name
>
> Changes in v4:
> - Use dma_slave_map to find the proper channel.
> - Explicitly call devm_request_irq() and tasklet_kill().
> - Fix namespace issue.
> - Some minor fixes and cleanups.
>
> Changes in v3:
> - Rename ls1x_dma_filter_fn to ls1x_dma_filter.
>
> Changes in v2:
> - Change the config from 'DMA_LOONGSON1' to 'LOONGSON1_DMA',
> - and rearrange it in alphabetical order in Kconfig and Makefile.
> - Fix comment style.
> ---
>  drivers/dma/Kconfig             |   9 +
>  drivers/dma/Makefile            |   1 +
>  drivers/dma/loongson1-apb-dma.c | 665 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 675 insertions(+)
>
> diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
> index 002a5ec80620..f7b06c4cdf3f 100644
> --- a/drivers/dma/Kconfig
> +++ b/drivers/dma/Kconfig
> @@ -369,6 +369,15 @@ config K3_DMA
>           Support the DMA engine for Hisilicon K3 platform
>           devices.
>
> +config LOONGSON1_APB_DMA
> +       tristate "Loongson1 APB DMA support"
> +       depends on MACH_LOONGSON32 || COMPILE_TEST
> +       select DMA_ENGINE
> +       select DMA_VIRTUAL_CHANNELS
> +       help
> +         This selects support for the APB DMA controller in Loongson1 SoCs,
> +         which is required by Loongson1 NAND and audio support.
Why not rename to LS1X_APB_DMA and put it just before LS2X_APB_DMA
(and also the driver file name)?

Huacai

> +
>  config LPC18XX_DMAMUX
>         bool "NXP LPC18xx/43xx DMA MUX for PL080"
>         depends on ARCH_LPC18XX || COMPILE_TEST
> diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
> index dfd40d14e408..b26f6677978a 100644
> --- a/drivers/dma/Makefile
> +++ b/drivers/dma/Makefile
> @@ -47,6 +47,7 @@ obj-$(CONFIG_INTEL_IDMA64) += idma64.o
>  obj-$(CONFIG_INTEL_IOATDMA) += ioat/
>  obj-y += idxd/
>  obj-$(CONFIG_K3_DMA) += k3dma.o
> +obj-$(CONFIG_LOONGSON1_APB_DMA) += loongson1-apb-dma.o
>  obj-$(CONFIG_LPC18XX_DMAMUX) += lpc18xx-dmamux.o
>  obj-$(CONFIG_LS2X_APB_DMA) += ls2x-apb-dma.o
>  obj-$(CONFIG_MILBEAUT_HDMAC) += milbeaut-hdmac.o
> diff --git a/drivers/dma/loongson1-apb-dma.c b/drivers/dma/loongson1-apb-dma.c
> new file mode 100644
> index 000000000000..d474a2601e6e
> --- /dev/null
> +++ b/drivers/dma/loongson1-apb-dma.c
> @@ -0,0 +1,665 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Driver for Loongson-1 APB DMA Controller
> + *
> + * Copyright (C) 2015-2024 Keguang Zhang <keguang.zhang@gmail.com>
> + */
> +
> +#include <linux/dmapool.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/iopoll.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_dma.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +
> +#include "dmaengine.h"
> +#include "virt-dma.h"
> +
> +/* Loongson-1 DMA Control Register */
> +#define DMA_CTRL                       0x0
> +
> +/* DMA Control Register Bits */
> +#define DMA_STOP                       BIT(4)
> +#define DMA_START                      BIT(3)
> +#define DMA_ASK_VALID                  BIT(2)
> +
> +#define DMA_ADDR_MASK                  GENMASK(31, 6)
> +
> +/* DMA Next Field Bits */
> +#define DMA_NEXT_VALID                 BIT(0)
> +
> +/* DMA Command Field Bits */
> +#define DMA_RAM2DEV                    BIT(12)
> +#define DMA_INT                                BIT(1)
> +#define DMA_INT_MASK                   BIT(0)
> +
> +#define LS1X_DMA_MAX_CHANNELS          3
> +
> +/* Size of allocations for hardware descriptors */
> +#define LS1X_DMA_DESCS_SIZE            PAGE_SIZE
> +#define LS1X_DMA_MAX_DESC              \
> +       (LS1X_DMA_DESCS_SIZE / sizeof(struct ls1x_dma_hwdesc))
> +
> +struct ls1x_dma_hwdesc {
> +       u32 next;               /* next descriptor address */
> +       u32 saddr;              /* memory DMA address */
> +       u32 daddr;              /* device DMA address */
> +       u32 length;
> +       u32 stride;
> +       u32 cycles;
> +       u32 cmd;
> +       u32 stats;
> +};
> +
> +struct ls1x_dma_desc {
> +       struct virt_dma_desc vdesc;
> +       enum dma_transfer_direction dir;
> +       enum dma_transaction_type type;
> +       unsigned int bus_width;
> +
> +       unsigned int nr_descs;  /* number of descriptors */
> +
> +       struct ls1x_dma_hwdesc *hwdesc;
> +       dma_addr_t hwdesc_phys;
> +};
> +
> +struct ls1x_dma_chan {
> +       struct virt_dma_chan vchan;
> +       struct dma_pool *desc_pool;
> +       phys_addr_t src_addr;
> +       phys_addr_t dst_addr;
> +       enum dma_slave_buswidth src_addr_width;
> +       enum dma_slave_buswidth dst_addr_width;
> +
> +       void __iomem *reg_base;
> +       int irq;
> +
> +       struct ls1x_dma_desc *desc;
> +
> +       struct ls1x_dma_hwdesc *curr_hwdesc;
> +       dma_addr_t curr_hwdesc_phys;
> +};
> +
> +struct ls1x_dma {
> +       struct dma_device ddev;
> +       void __iomem *reg_base;
> +
> +       unsigned int nr_chans;
> +       struct ls1x_dma_chan chan[];
> +};
> +
> +#define to_ls1x_dma_chan(dchan)                \
> +       container_of(dchan, struct ls1x_dma_chan, vchan.chan)
> +
> +#define to_ls1x_dma_desc(vd)           \
> +       container_of(vd, struct ls1x_dma_desc, vdesc)
> +
> +/* macros for registers read/write */
> +#define chan_readl(chan, off)          \
> +       readl((chan)->reg_base + (off))
> +
> +#define chan_writel(chan, off, val)    \
> +       writel((val), (chan)->reg_base + (off))
> +
> +static inline struct device *chan2dev(struct dma_chan *chan)
> +{
> +       return &chan->dev->device;
> +}
> +
> +static inline int ls1x_dma_query(struct ls1x_dma_chan *chan,
> +                                dma_addr_t *hwdesc_phys)
> +{
> +       struct dma_chan *dchan = &chan->vchan.chan;
> +       int val, ret;
> +
> +       val = *hwdesc_phys & DMA_ADDR_MASK;
> +       val |= DMA_ASK_VALID;
> +       val |= dchan->chan_id;
> +       chan_writel(chan, DMA_CTRL, val);
> +       ret = readl_poll_timeout_atomic(chan->reg_base + DMA_CTRL, val,
> +                                       !(val & DMA_ASK_VALID), 0, 3000);
> +       if (ret)
> +               dev_err(chan2dev(dchan), "failed to query DMA\n");
> +
> +       return ret;
> +}
> +
> +static inline int ls1x_dma_start(struct ls1x_dma_chan *chan,
> +                                dma_addr_t *hwdesc_phys)
> +{
> +       struct dma_chan *dchan = &chan->vchan.chan;
> +       int val, ret;
> +
> +       dev_dbg(chan2dev(dchan), "cookie=%d, starting hwdesc=%x\n",
> +               dchan->cookie, *hwdesc_phys);
> +
> +       val = *hwdesc_phys & DMA_ADDR_MASK;
> +       val |= DMA_START;
> +       val |= dchan->chan_id;
> +       chan_writel(chan, DMA_CTRL, val);
> +       ret = readl_poll_timeout(chan->reg_base + DMA_CTRL, val,
> +                                !(val & DMA_START), 0, 3000);
> +       if (ret)
> +               dev_err(chan2dev(dchan), "failed to start DMA\n");
> +
> +       return ret;
> +}
> +
> +static inline void ls1x_dma_stop(struct ls1x_dma_chan *chan)
> +{
> +       chan_writel(chan, DMA_CTRL, chan_readl(chan, DMA_CTRL) | DMA_STOP);
> +}
> +
> +static void ls1x_dma_free_chan_resources(struct dma_chan *dchan)
> +{
> +       struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
> +
> +       dma_free_coherent(chan2dev(dchan), sizeof(struct ls1x_dma_hwdesc),
> +                         chan->curr_hwdesc, chan->curr_hwdesc_phys);
> +       vchan_free_chan_resources(&chan->vchan);
> +       dma_pool_destroy(chan->desc_pool);
> +       chan->desc_pool = NULL;
> +}
> +
> +static int ls1x_dma_alloc_chan_resources(struct dma_chan *dchan)
> +{
> +       struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
> +
> +       chan->desc_pool = dma_pool_create(dma_chan_name(dchan),
> +                                         chan2dev(dchan),
> +                                         sizeof(struct ls1x_dma_hwdesc),
> +                                         __alignof__(struct ls1x_dma_hwdesc),
> +                                         0);
> +       if (!chan->desc_pool)
> +               return -ENOMEM;
> +
> +       /* allocate memory for querying current HW descriptor */
> +       dma_set_coherent_mask(chan2dev(dchan), DMA_BIT_MASK(32));
> +       chan->curr_hwdesc = dma_alloc_coherent(chan2dev(dchan),
> +                                              sizeof(struct ls1x_dma_hwdesc),
> +                                              &chan->curr_hwdesc_phys,
> +                                              GFP_KERNEL);
> +       if (!chan->curr_hwdesc)
> +               return -ENOMEM;
> +
> +       return 0;
> +}
> +
> +static void ls1x_dma_free_desc(struct virt_dma_desc *vdesc)
> +{
> +       struct ls1x_dma_desc *desc = to_ls1x_dma_desc(vdesc);
> +       struct ls1x_dma_chan *chan = to_ls1x_dma_chan(vdesc->tx.chan);
> +
> +       dma_pool_free(chan->desc_pool, desc->hwdesc, desc->hwdesc_phys);
> +       chan->desc = NULL;
> +       kfree(desc);
> +}
> +
> +static struct ls1x_dma_desc *
> +ls1x_dma_alloc_desc(struct dma_chan *dchan, int sg_len,
> +                   enum dma_transfer_direction direction,
> +                   enum dma_transaction_type type)
> +{
> +       struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
> +       struct ls1x_dma_desc *desc;
> +
> +       if (sg_len > LS1X_DMA_MAX_DESC) {
> +               dev_err(chan2dev(dchan), "sg_len %u exceeds limit %lu",
> +                       sg_len, LS1X_DMA_MAX_DESC);
> +               return NULL;
> +       }
> +
> +       desc = kzalloc(sizeof(*desc), GFP_NOWAIT);
> +       if (!desc)
> +               return NULL;
> +
> +       /* allocate HW descriptors */
> +       desc->hwdesc = dma_pool_zalloc(chan->desc_pool, GFP_NOWAIT,
> +                                      &desc->hwdesc_phys);
> +       if (!desc->hwdesc) {
> +               dev_err(chan2dev(dchan), "failed to alloc HW descriptors\n");
> +               ls1x_dma_free_desc(&desc->vdesc);
> +               return NULL;
> +       }
> +
> +       desc->dir = direction;
> +       desc->type = type;
> +       desc->nr_descs = sg_len;
> +
> +       return desc;
> +}
> +
> +static int ls1x_dma_setup_hwdescs(struct dma_chan *dchan,
> +                                 struct ls1x_dma_desc *desc,
> +                                 struct scatterlist *sgl, unsigned int sg_len)
> +{
> +       struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
> +       dma_addr_t next_hwdesc_phys = desc->hwdesc_phys;
> +
> +       struct scatterlist *sg;
> +       unsigned int dev_addr, cmd, i;
> +
> +       switch (desc->dir) {
> +       case DMA_MEM_TO_DEV:
> +               dev_addr = chan->dst_addr;
> +               desc->bus_width = chan->dst_addr_width;
> +               cmd = DMA_RAM2DEV | DMA_INT;
> +               break;
> +       case DMA_DEV_TO_MEM:
> +               dev_addr = chan->src_addr;
> +               desc->bus_width = chan->src_addr_width;
> +               cmd = DMA_INT;
> +               break;
> +       default:
> +               dev_err(chan2dev(dchan), "unsupported DMA direction: %s\n",
> +                       dmaengine_get_direction_text(desc->dir));
> +               return -EINVAL;
> +       }
> +
> +       /* setup HW descriptors */
> +       for_each_sg(sgl, sg, sg_len, i) {
> +               dma_addr_t buf_addr = sg_dma_address(sg);
> +               size_t buf_len = sg_dma_len(sg);
> +               struct ls1x_dma_hwdesc *hwdesc = &desc->hwdesc[i];
> +
> +               if (!is_dma_copy_aligned(dchan->device, buf_addr, 0, buf_len)) {
> +                       dev_err(chan2dev(dchan), "buffer is not aligned!\n");
> +                       return -EINVAL;
> +               }
> +
> +               hwdesc->saddr = buf_addr;
> +               hwdesc->daddr = dev_addr;
> +               hwdesc->length = buf_len / desc->bus_width;
> +               hwdesc->stride = 0;
> +               hwdesc->cycles = 1;
> +               hwdesc->cmd = cmd;
> +
> +               if (i) {
> +                       next_hwdesc_phys += sizeof(*hwdesc);
> +                       desc->hwdesc[i - 1].next = next_hwdesc_phys
> +                           | DMA_NEXT_VALID;
> +               }
> +       }
> +
> +       if (desc->type == DMA_CYCLIC)
> +               desc->hwdesc[i - 1].next = desc->hwdesc_phys | DMA_NEXT_VALID;
> +
> +       for_each_sg(sgl, sg, sg_len, i) {
> +               struct ls1x_dma_hwdesc *hwdesc = &desc->hwdesc[i];
> +
> +               print_hex_dump_debug("HW DESC: ", DUMP_PREFIX_OFFSET, 16, 4,
> +                                    hwdesc, sizeof(*hwdesc), false);
> +       }
> +
> +       return 0;
> +}
> +
> +static struct dma_async_tx_descriptor *
> +ls1x_dma_prep_slave_sg(struct dma_chan *dchan,
> +                      struct scatterlist *sgl, unsigned int sg_len,
> +                      enum dma_transfer_direction direction,
> +                      unsigned long flags, void *context)
> +{
> +       struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
> +       struct ls1x_dma_desc *desc;
> +
> +       dev_dbg(chan2dev(dchan), "sg_len=%u flags=0x%lx dir=%s\n",
> +               sg_len, flags, dmaengine_get_direction_text(direction));
> +
> +       desc = ls1x_dma_alloc_desc(dchan, sg_len, direction, DMA_SLAVE);
> +       if (!desc)
> +               return NULL;
> +
> +       if (ls1x_dma_setup_hwdescs(dchan, desc, sgl, sg_len)) {
> +               ls1x_dma_free_desc(&desc->vdesc);
> +               return NULL;
> +       }
> +
> +       return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
> +}
> +
> +static struct dma_async_tx_descriptor *
> +ls1x_dma_prep_dma_cyclic(struct dma_chan *dchan,
> +                        dma_addr_t buf_addr, size_t buf_len, size_t period_len,
> +                        enum dma_transfer_direction direction,
> +                        unsigned long flags)
> +{
> +       struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
> +       struct ls1x_dma_desc *desc;
> +       struct scatterlist *sgl;
> +       unsigned int sg_len;
> +       unsigned int i;
> +
> +       dev_dbg(chan2dev(dchan),
> +               "buf_len=%d period_len=%zu flags=0x%lx dir=%s\n", buf_len,
> +               period_len, flags, dmaengine_get_direction_text(direction));
> +
> +       sg_len = buf_len / period_len;
> +       desc = ls1x_dma_alloc_desc(dchan, sg_len, direction, DMA_CYCLIC);
> +       if (!desc)
> +               return NULL;
> +
> +       /* allocate the scatterlist */
> +       sgl = kmalloc_array(sg_len, sizeof(*sgl), GFP_NOWAIT);
> +       if (!sgl)
> +               return NULL;
> +
> +       sg_init_table(sgl, sg_len);
> +       for (i = 0; i < sg_len; ++i) {
> +               sg_set_page(&sgl[i], pfn_to_page(PFN_DOWN(buf_addr)),
> +                           period_len, offset_in_page(buf_addr));
> +               sg_dma_address(&sgl[i]) = buf_addr;
> +               sg_dma_len(&sgl[i]) = period_len;
> +               buf_addr += period_len;
> +       }
> +
> +       if (ls1x_dma_setup_hwdescs(dchan, desc, sgl, sg_len)) {
> +               ls1x_dma_free_desc(&desc->vdesc);
> +               return NULL;
> +       }
> +
> +       kfree(sgl);
> +
> +       return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
> +}
> +
> +static int ls1x_dma_slave_config(struct dma_chan *dchan,
> +                                struct dma_slave_config *config)
> +{
> +       struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
> +
> +       chan->src_addr = config->src_addr;
> +       chan->src_addr_width = config->src_addr_width;
> +       chan->dst_addr = config->dst_addr;
> +       chan->dst_addr_width = config->dst_addr_width;
> +
> +       return 0;
> +}
> +
> +static int ls1x_dma_pause(struct dma_chan *dchan)
> +{
> +       struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
> +       unsigned long flags;
> +       int ret;
> +
> +       spin_lock_irqsave(&chan->vchan.lock, flags);
> +       ret = ls1x_dma_query(chan, &chan->curr_hwdesc_phys);
> +       if (!ret)
> +               ls1x_dma_stop(chan);
> +       spin_unlock_irqrestore(&chan->vchan.lock, flags);
> +
> +       return ret;
> +}
> +
> +static int ls1x_dma_resume(struct dma_chan *dchan)
> +{
> +       struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
> +       unsigned long flags;
> +       int ret;
> +
> +       spin_lock_irqsave(&chan->vchan.lock, flags);
> +       ret = ls1x_dma_start(chan, &chan->curr_hwdesc_phys);
> +       spin_unlock_irqrestore(&chan->vchan.lock, flags);
> +
> +       return ret;
> +}
> +
> +static int ls1x_dma_terminate_all(struct dma_chan *dchan)
> +{
> +       struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
> +       unsigned long flags;
> +       LIST_HEAD(head);
> +
> +       spin_lock_irqsave(&chan->vchan.lock, flags);
> +       ls1x_dma_stop(chan);
> +       vchan_get_all_descriptors(&chan->vchan, &head);
> +       spin_unlock_irqrestore(&chan->vchan.lock, flags);
> +
> +       vchan_dma_desc_free_list(&chan->vchan, &head);
> +
> +       return 0;
> +}
> +
> +static enum dma_status ls1x_dma_tx_status(struct dma_chan *dchan,
> +                                         dma_cookie_t cookie,
> +                                         struct dma_tx_state *state)
> +{
> +       struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
> +       struct virt_dma_desc *vdesc;
> +       enum dma_status status;
> +       size_t bytes = 0;
> +       unsigned long flags;
> +
> +       status = dma_cookie_status(dchan, cookie, state);
> +       if (status == DMA_COMPLETE)
> +               return status;
> +
> +       spin_lock_irqsave(&chan->vchan.lock, flags);
> +       vdesc = vchan_find_desc(&chan->vchan, cookie);
> +       if (chan->desc && cookie == chan->desc->vdesc.tx.cookie) {
> +               struct ls1x_dma_desc *desc = chan->desc;
> +               int i;
> +
> +               if (ls1x_dma_query(chan, &chan->curr_hwdesc_phys))
> +                       return status;
> +
> +               /* locate the current HW descriptor */
> +               for (i = 0; i < desc->nr_descs; i++)
> +                       if (desc->hwdesc[i].next == chan->curr_hwdesc->next)
> +                               break;
> +
> +               /* count the residues */
> +               for (; i < desc->nr_descs; i++)
> +                       bytes += desc->hwdesc[i].length * desc->bus_width;
> +
> +               dma_set_residue(state, bytes);
> +       }
> +       spin_unlock_irqrestore(&chan->vchan.lock, flags);
> +
> +       return status;
> +}
> +
> +static void ls1x_dma_issue_pending(struct dma_chan *dchan)
> +{
> +       struct ls1x_dma_chan *chan = to_ls1x_dma_chan(dchan);
> +       struct virt_dma_desc *vdesc;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&chan->vchan.lock, flags);
> +       if (vchan_issue_pending(&chan->vchan) && !chan->desc) {
> +               vdesc = vchan_next_desc(&chan->vchan);
> +               if (!vdesc) {
> +                       chan->desc = NULL;
> +                       return;
> +               }
> +               chan->desc = to_ls1x_dma_desc(vdesc);
> +               ls1x_dma_start(chan, &chan->desc->hwdesc_phys);
> +       }
> +       spin_unlock_irqrestore(&chan->vchan.lock, flags);
> +}
> +
> +static irqreturn_t ls1x_dma_irq_handler(int irq, void *data)
> +{
> +       struct ls1x_dma_chan *chan = data;
> +       struct ls1x_dma_desc *desc = chan->desc;
> +       struct dma_chan *dchan = &chan->vchan.chan;
> +
> +       if (!desc) {
> +               dev_warn(chan2dev(dchan),
> +                        "IRQ %d with no active descriptor on channel %d\n",
> +                        irq, dchan->chan_id);
> +               return IRQ_NONE;
> +       }
> +
> +       dev_dbg(chan2dev(dchan), "DMA IRQ %d on channel %d\n", irq,
> +               dchan->chan_id);
> +
> +       spin_lock(&chan->vchan.lock);
> +
> +       if (desc->type == DMA_CYCLIC) {
> +               vchan_cyclic_callback(&desc->vdesc);
> +       } else {
> +               list_del(&desc->vdesc.node);
> +               vchan_cookie_complete(&desc->vdesc);
> +               chan->desc = NULL;
> +       }
> +
> +       spin_unlock(&chan->vchan.lock);
> +       return IRQ_HANDLED;
> +}
> +
> +static int ls1x_dma_chan_probe(struct platform_device *pdev,
> +                              struct ls1x_dma *dma, int chan_id)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct ls1x_dma_chan *chan = &dma->chan[chan_id];
> +       char pdev_irqname[4];
> +       char *irqname;
> +       int ret;
> +
> +       sprintf(pdev_irqname, "ch%u", chan_id);
> +       chan->irq = platform_get_irq_byname(pdev, pdev_irqname);
> +       if (chan->irq < 0)
> +               return -ENODEV;
> +
> +       irqname = devm_kasprintf(dev, GFP_KERNEL, "%s:%s",
> +                                dev_name(dev), pdev_irqname);
> +       if (!irqname)
> +               return -ENOMEM;
> +
> +       ret = devm_request_irq(dev, chan->irq, ls1x_dma_irq_handler,
> +                              IRQF_SHARED, irqname, chan);
> +       if (ret)
> +               return dev_err_probe(dev, ret,
> +                                    "failed to request IRQ %u!\n", chan->irq);
> +
> +       chan->reg_base = dma->reg_base;
> +       chan->vchan.desc_free = ls1x_dma_free_desc;
> +       vchan_init(&chan->vchan, &dma->ddev);
> +       dev_info(dev, "%s (irq %d) initialized\n", pdev_irqname, chan->irq);
> +
> +       return 0;
> +}
> +
> +static void ls1x_dma_chan_remove(struct ls1x_dma *dma, int chan_id)
> +{
> +       struct device *dev = dma->ddev.dev;
> +       struct ls1x_dma_chan *chan = &dma->chan[chan_id];
> +
> +       devm_free_irq(dev, chan->irq, chan);
> +       list_del(&chan->vchan.chan.device_node);
> +       tasklet_kill(&chan->vchan.task);
> +}
> +
> +static int ls1x_dma_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct dma_device *ddev;
> +       struct ls1x_dma *dma;
> +       int nr_chans, ret, i;
> +
> +       nr_chans = platform_irq_count(pdev);
> +       if (nr_chans <= 0)
> +               return nr_chans;
> +       if (nr_chans > LS1X_DMA_MAX_CHANNELS)
> +               return dev_err_probe(dev, -EINVAL,
> +                                    "nr_chans=%d exceeds the maximum\n",
> +                                    nr_chans);
> +
> +       dma = devm_kzalloc(dev, struct_size(dma, chan, nr_chans), GFP_KERNEL);
> +       if (!dma)
> +               return -ENOMEM;
> +
> +       /* initialize DMA device */
> +       dma->reg_base = devm_platform_ioremap_resource(pdev, 0);
> +       if (IS_ERR(dma->reg_base))
> +               return PTR_ERR(dma->reg_base);
> +
> +       ddev = &dma->ddev;
> +       ddev->dev = dev;
> +       ddev->copy_align = DMAENGINE_ALIGN_4_BYTES;
> +       ddev->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
> +           BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
> +       ddev->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
> +           BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
> +       ddev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
> +       ddev->max_sg_burst = LS1X_DMA_MAX_DESC;
> +       ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
> +       ddev->device_alloc_chan_resources = ls1x_dma_alloc_chan_resources;
> +       ddev->device_free_chan_resources = ls1x_dma_free_chan_resources;
> +       ddev->device_prep_slave_sg = ls1x_dma_prep_slave_sg;
> +       ddev->device_prep_dma_cyclic = ls1x_dma_prep_dma_cyclic;
> +       ddev->device_config = ls1x_dma_slave_config;
> +       ddev->device_pause = ls1x_dma_pause;
> +       ddev->device_resume = ls1x_dma_resume;
> +       ddev->device_terminate_all = ls1x_dma_terminate_all;
> +       ddev->device_tx_status = ls1x_dma_tx_status;
> +       ddev->device_issue_pending = ls1x_dma_issue_pending;
> +
> +       dma_cap_set(DMA_SLAVE, ddev->cap_mask);
> +       INIT_LIST_HEAD(&ddev->channels);
> +
> +       /* initialize DMA channels */
> +       for (i = 0; i < nr_chans; i++) {
> +               ret = ls1x_dma_chan_probe(pdev, dma, i);
> +               if (ret)
> +                       return ret;
> +       }
> +       dma->nr_chans = nr_chans;
> +
> +       ret = dmaenginem_async_device_register(ddev);
> +       if (ret) {
> +               dev_err(dev, "failed to register DMA device! %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret =
> +           of_dma_controller_register(dev->of_node, of_dma_xlate_by_chan_id,
> +                                      ddev);
> +       if (ret) {
> +               dev_err(dev, "failed to register DMA controller! %d\n", ret);
> +               return ret;
> +       }
> +
> +       platform_set_drvdata(pdev, dma);
> +       dev_info(dev, "Loongson1 DMA driver registered\n");
> +
> +       return 0;
> +}
> +
> +static void ls1x_dma_remove(struct platform_device *pdev)
> +{
> +       struct ls1x_dma *dma = platform_get_drvdata(pdev);
> +       int i;
> +
> +       of_dma_controller_free(pdev->dev.of_node);
> +
> +       for (i = 0; i < dma->nr_chans; i++)
> +               ls1x_dma_chan_remove(dma, i);
> +}
> +
> +static const struct of_device_id ls1x_dma_match[] = {
> +       { .compatible = "loongson,ls1b-apbdma" },
> +       { .compatible = "loongson,ls1c-apbdma" },
> +       { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, ls1x_dma_match);
> +
> +static struct platform_driver ls1x_dma_driver = {
> +       .probe = ls1x_dma_probe,
> +       .remove_new = ls1x_dma_remove,
> +       .driver = {
> +               .name = KBUILD_MODNAME,
> +               .of_match_table = ls1x_dma_match,
> +       },
> +};
> +
> +module_platform_driver(ls1x_dma_driver);
> +
> +MODULE_AUTHOR("Keguang Zhang <keguang.zhang@gmail.com>");
> +MODULE_DESCRIPTION("Loongson-1 APB DMA Controller driver");
> +MODULE_LICENSE("GPL");
>
> --
> 2.40.1
>
>

^ permalink raw reply

* Re: [RFC PATCH 0/2] Add gpio-usb-c-connector compatible
From: Dmitry Baryshkov @ 2024-03-30 13:50 UTC (permalink / raw)
  To: Krishna Kurapati PSSNV
  Cc: Rob Herring, Krzysztof Kozlowski, Greg Kroah-Hartman,
	Conor Dooley, Miquel Raynal, Guenter Roeck, Bjorn Helgaas,
	Kyle Tso, Fabrice Gasnier, Heikki Krogerus, u.kleine-koenig,
	AngeloGioacchino Del Regno, devicetree, linux-usb, linux-kernel,
	quic_ppratap, quic_jackp
In-Reply-To: <44bc6ea4-eba9-4b80-bb07-3b744eb7cce6@quicinc.com>

On Sat, 30 Mar 2024 at 15:46, Krishna Kurapati PSSNV
<quic_kriskura@quicinc.com> wrote:
>
>
>
> On 3/30/2024 7:09 PM, Dmitry Baryshkov wrote:
> > On Sat, 30 Mar 2024 at 11:13, Krishna Kurapati PSSNV
> > <quic_kriskura@quicinc.com> wrote:
> >> On 3/29/2024 6:23 PM, Dmitry Baryshkov wrote:
> >>> On Fri, 29 Mar 2024 at 09:20, Krishna Kurapati
> >>> <quic_kriskura@quicinc.com> wrote:
> >>>>
> >>>> QDU1000 IDP [1] has a Type-c connector and supports USB 3.0.
> >>>> However it relies on usb-conn-gpio driver to read the vbus and id
> >>>> gpio's and provide role switch. However the driver currently has
> >>>> only gpio-b-connector compatible present in ID table. Adding that
> >>>> in DT would mean that the device supports Type-B connector and not
> >>>> Type-c connector. Thanks to Dmitry Baryshkov for pointing it out [2].
> >>>
> >>> USB-B connector is pretty simple, it really has just an ID pin and
> >>> VBUS input, which translates to two GPIOs being routed from the
> >>> _connector_ itself.
> >>>
> >>> USB-C is much more complicated, it has two CC pins and a VBus power
> >>> pin. It is not enough just to measure CC pin levels. Moreover,
> >>> properly handling USB 3.0 inside a USB-C connector requires a separate
> >>> 'orientation' signal to tell the host which two lanes must be used for
> >>> the USB SS signals. Thus it is no longer possible to route just two
> >>> pins from the connector to the SoC.
> >>>
> >>> Having all that in mind, I suspect that you are not describing your
> >>> hardware properly. I suppose that you have a Type-C port controller /
> >>> redriver / switch, which handles CC lines communication and then
> >>> provides ID / VBUS signals to the host. In such a case, please
> >>> describe this TCPC in the DT file and use its compatible string
> >>> instead of "gpio-c-connector".
> >>>
> >>
> >> Hi Dmitry,
> >>
> >>    My bad. I must have provided more details of the HW.
> >>
> >>    I presume you are referring to addition of a connector node, type-c
> >> switch, pmic-glink and other remote endpoints like in other SoC's like
> >> SM8450/ SM8550/ SM8650.
> >>
> >>    This HW is slightly different. It has a Uni Phy for Super speed and
> >> hence no DP.
> >
> > This is fine and it's irrelevant for the USB-C.
> >
> >>    For orientation switching, on mobile SoC's, there is a provision for
> >> orientation gpio given in pmic-glink node and is handled in ucsi_glink
> >> driver. But on this version of HW, there is a USB-C Switch with its own
> >> firmware taking care of orientation switching. It takes 8 SS Lines and 2
> >> CC lines coming from connector as input and gives out 4 SS Lines (SS
> >> TX1/TX2 RX1/RX2) as output which go to the SoC. So orientation switch is
> >> done by the USB-C-switch in between and it automatically routes
> >> appropriate active SS Lane from connector to the SoC.
> >
> > This is also fine. As I wrote, you _have_ the Type-C port controller.
> > So your DT file should be describing your hardware.
> >
> >>    As usual like in other targets, the DP and DM lines from type-c
> >> connector go to the SoC directly.
> >>
> >>    To handle role switch, the VBUS and ID Pin connections are given to
> >> SoC as well. There is a vbus controller regulator present to provide
> >> vbus to connected peripherals in host mode.
> >>
> >>    There is no PPM entity (ADSP in mobile SoC's) and no UCSI involved
> >> here. Hence we rely on usb-conn-gpio to read the vbus/id and switch
> >> roles accordingly.
> >
> > This is also fine.
> >
> > You confirmed my suspicions. You have an external Type-C switch which
> > handles orientation (and most likely PD or non-PD power negotiation)
> > for you. It has GPIO outputs, etc.
> >
> > But it is not a part of the connector. Instead of adding the
> > "gpio-usb-c-connector", add proper compatible string (see, how this is
> > handled e.g. by the spidev - it is a generic driver, but it requires
> > hardware-specific compatibles).
> > Your hardware description should look like:
> >
> > typec {
> >      compatible = "your,switch";
> >      id-gpios = <&gpio 1>;
> >      vbus-gpios = <&gpio 2>;
> >      vbus-supplies = <&reg-vbus>;
> >
> >      ports {
> >         #address-cells = <1>;
> >         #size-cells = <1>;
> >         port@0 {
> >            endpoint {
> >                remote-endpoint = <&usb_dwc3_hs_out>;
> >            };
> >         };
> >         port@1 {
> >            endpoint {
> >                remote-endpoint = <&usb_uni_phy_out>;
> >            };
> >        };
> >        /* No SBU port */
> >     };
> > };
> >  > Note, I haven't said anything regarding the driver. You can continue
> > using the usb-conn-gpio driver. Just add a compatible string for you
> > switch.
> >
>
>
> Got it. So the "usb_conn_gpio: usb-conn-gpio" in [1]  to be replaced
> with something like a "typec- " naming convention and add a new
> compatible to gpio-conn (something specific to qcom-qdu) and use it in
> the new DT node.

It should be the actual name of the switch chip.

>
> Thanks for the suggestion. Is it fine if it put the whole of the above
> text in v2 and push it for getting a new compatible added to connector
> binding and usb-conn driver and then send v3 of DT changes or mix this
> series with the DT series ?

I think USB subsystem maintainers prefer separate series.

>
> [1]:
> https://lore.kernel.org/all/20240319091020.15137-3-quic_kbajaj@quicinc.com/
>
> Thanks,
> Krishna,
>
> >>
> >>    Hope this answers the query as to why we wanted to use usb-conn-gpio
> >> and why we were trying to add a new compatible.
> >>
> >> Regards,
> >> Krishna,
> >>
> >>>>
> >>>> This series intends to add that compatible in driver and bindings
> >>>> so that it can be used in QDU1000 IDP DT.
> >>>>
> >>>> [1]: https://lore.kernel.org/all/20240319091020.15137-3-quic_kbajaj@quicinc.com/
> >>>> [2]: https://lore.kernel.org/all/CAA8EJprXPvji8TgZu1idH7y4GtHtD4VmQABFBcRt-9BQaCberg@mail.gmail.com/
> >>>>
> >>>> Krishna Kurapati (2):
> >>>>     dt-bindings: connector: Add gpio-usb-c-connector compatible
> >>>>     usb: common: usb-conn-gpio: Update ID table to add usb-c connector
> >>>>
> >>>>    Documentation/devicetree/bindings/connector/usb-connector.yaml | 3 +++
> >>>>    drivers/usb/common/usb-conn-gpio.c                             | 1 +
> >>>>    2 files changed, 4 insertions(+)
> >>>>
> >>>> --
> >>>> 2.34.1
> >>>>
> >>>
> >>>
> >>> --
> >>> With best wishes
> >>> Dmitry
> >
> >
> >



-- 
With best wishes
Dmitry

^ permalink raw reply

* Re: [RFC PATCH 0/2] Add gpio-usb-c-connector compatible
From: Krishna Kurapati PSSNV @ 2024-03-30 13:45 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: Rob Herring, Krzysztof Kozlowski, Greg Kroah-Hartman,
	Conor Dooley, Miquel Raynal, Guenter Roeck, Bjorn Helgaas,
	Kyle Tso, Fabrice Gasnier, Heikki Krogerus, u.kleine-koenig,
	AngeloGioacchino Del Regno, devicetree, linux-usb, linux-kernel,
	quic_ppratap, quic_jackp
In-Reply-To: <CAA8EJppa4hVBSenLgxc5MYxTfzPPf4exHvh8RWTP=p8mgB_RCw@mail.gmail.com>



On 3/30/2024 7:09 PM, Dmitry Baryshkov wrote:
> On Sat, 30 Mar 2024 at 11:13, Krishna Kurapati PSSNV
> <quic_kriskura@quicinc.com> wrote:
>> On 3/29/2024 6:23 PM, Dmitry Baryshkov wrote:
>>> On Fri, 29 Mar 2024 at 09:20, Krishna Kurapati
>>> <quic_kriskura@quicinc.com> wrote:
>>>>
>>>> QDU1000 IDP [1] has a Type-c connector and supports USB 3.0.
>>>> However it relies on usb-conn-gpio driver to read the vbus and id
>>>> gpio's and provide role switch. However the driver currently has
>>>> only gpio-b-connector compatible present in ID table. Adding that
>>>> in DT would mean that the device supports Type-B connector and not
>>>> Type-c connector. Thanks to Dmitry Baryshkov for pointing it out [2].
>>>
>>> USB-B connector is pretty simple, it really has just an ID pin and
>>> VBUS input, which translates to two GPIOs being routed from the
>>> _connector_ itself.
>>>
>>> USB-C is much more complicated, it has two CC pins and a VBus power
>>> pin. It is not enough just to measure CC pin levels. Moreover,
>>> properly handling USB 3.0 inside a USB-C connector requires a separate
>>> 'orientation' signal to tell the host which two lanes must be used for
>>> the USB SS signals. Thus it is no longer possible to route just two
>>> pins from the connector to the SoC.
>>>
>>> Having all that in mind, I suspect that you are not describing your
>>> hardware properly. I suppose that you have a Type-C port controller /
>>> redriver / switch, which handles CC lines communication and then
>>> provides ID / VBUS signals to the host. In such a case, please
>>> describe this TCPC in the DT file and use its compatible string
>>> instead of "gpio-c-connector".
>>>
>>
>> Hi Dmitry,
>>
>>    My bad. I must have provided more details of the HW.
>>
>>    I presume you are referring to addition of a connector node, type-c
>> switch, pmic-glink and other remote endpoints like in other SoC's like
>> SM8450/ SM8550/ SM8650.
>>
>>    This HW is slightly different. It has a Uni Phy for Super speed and
>> hence no DP.
> 
> This is fine and it's irrelevant for the USB-C.
> 
>>    For orientation switching, on mobile SoC's, there is a provision for
>> orientation gpio given in pmic-glink node and is handled in ucsi_glink
>> driver. But on this version of HW, there is a USB-C Switch with its own
>> firmware taking care of orientation switching. It takes 8 SS Lines and 2
>> CC lines coming from connector as input and gives out 4 SS Lines (SS
>> TX1/TX2 RX1/RX2) as output which go to the SoC. So orientation switch is
>> done by the USB-C-switch in between and it automatically routes
>> appropriate active SS Lane from connector to the SoC.
> 
> This is also fine. As I wrote, you _have_ the Type-C port controller.
> So your DT file should be describing your hardware.
> 
>>    As usual like in other targets, the DP and DM lines from type-c
>> connector go to the SoC directly.
>>
>>    To handle role switch, the VBUS and ID Pin connections are given to
>> SoC as well. There is a vbus controller regulator present to provide
>> vbus to connected peripherals in host mode.
>>
>>    There is no PPM entity (ADSP in mobile SoC's) and no UCSI involved
>> here. Hence we rely on usb-conn-gpio to read the vbus/id and switch
>> roles accordingly.
> 
> This is also fine.
> 
> You confirmed my suspicions. You have an external Type-C switch which
> handles orientation (and most likely PD or non-PD power negotiation)
> for you. It has GPIO outputs, etc.
> 
> But it is not a part of the connector. Instead of adding the
> "gpio-usb-c-connector", add proper compatible string (see, how this is
> handled e.g. by the spidev - it is a generic driver, but it requires
> hardware-specific compatibles).
> Your hardware description should look like:
> 
> typec {
>      compatible = "your,switch";
>      id-gpios = <&gpio 1>;
>      vbus-gpios = <&gpio 2>;
>      vbus-supplies = <&reg-vbus>;
> 
>      ports {
>         #address-cells = <1>;
>         #size-cells = <1>;
>         port@0 {
>            endpoint {
>                remote-endpoint = <&usb_dwc3_hs_out>;
>            };
>         };
>         port@1 {
>            endpoint {
>                remote-endpoint = <&usb_uni_phy_out>;
>            };
>        };
>        /* No SBU port */
>     };
> };
>  > Note, I haven't said anything regarding the driver. You can continue
> using the usb-conn-gpio driver. Just add a compatible string for you
> switch.
> 


Got it. So the "usb_conn_gpio: usb-conn-gpio" in [1]  to be replaced 
with something like a "typec- " naming convention and add a new 
compatible to gpio-conn (something specific to qcom-qdu) and use it in 
the new DT node.

Thanks for the suggestion. Is it fine if it put the whole of the above 
text in v2 and push it for getting a new compatible added to connector 
binding and usb-conn driver and then send v3 of DT changes or mix this 
series with the DT series ?

[1]: 
https://lore.kernel.org/all/20240319091020.15137-3-quic_kbajaj@quicinc.com/

Thanks,
Krishna,

>>
>>    Hope this answers the query as to why we wanted to use usb-conn-gpio
>> and why we were trying to add a new compatible.
>>
>> Regards,
>> Krishna,
>>
>>>>
>>>> This series intends to add that compatible in driver and bindings
>>>> so that it can be used in QDU1000 IDP DT.
>>>>
>>>> [1]: https://lore.kernel.org/all/20240319091020.15137-3-quic_kbajaj@quicinc.com/
>>>> [2]: https://lore.kernel.org/all/CAA8EJprXPvji8TgZu1idH7y4GtHtD4VmQABFBcRt-9BQaCberg@mail.gmail.com/
>>>>
>>>> Krishna Kurapati (2):
>>>>     dt-bindings: connector: Add gpio-usb-c-connector compatible
>>>>     usb: common: usb-conn-gpio: Update ID table to add usb-c connector
>>>>
>>>>    Documentation/devicetree/bindings/connector/usb-connector.yaml | 3 +++
>>>>    drivers/usb/common/usb-conn-gpio.c                             | 1 +
>>>>    2 files changed, 4 insertions(+)
>>>>
>>>> --
>>>> 2.34.1
>>>>
>>>
>>>
>>> --
>>> With best wishes
>>> Dmitry
> 
> 
> 

^ permalink raw reply

* Re: [RFC PATCH 0/2] Add gpio-usb-c-connector compatible
From: Dmitry Baryshkov @ 2024-03-30 13:39 UTC (permalink / raw)
  To: Krishna Kurapati PSSNV
  Cc: Rob Herring, Krzysztof Kozlowski, Greg Kroah-Hartman,
	Conor Dooley, Miquel Raynal, Guenter Roeck, Bjorn Helgaas,
	Kyle Tso, Fabrice Gasnier, Heikki Krogerus, u.kleine-koenig,
	AngeloGioacchino Del Regno, devicetree, linux-usb, linux-kernel,
	quic_ppratap, quic_jackp
In-Reply-To: <6f2df222-36d4-468e-99a7-9c48fae85aa9@quicinc.com>

On Sat, 30 Mar 2024 at 11:13, Krishna Kurapati PSSNV
<quic_kriskura@quicinc.com> wrote:
> On 3/29/2024 6:23 PM, Dmitry Baryshkov wrote:
> > On Fri, 29 Mar 2024 at 09:20, Krishna Kurapati
> > <quic_kriskura@quicinc.com> wrote:
> >>
> >> QDU1000 IDP [1] has a Type-c connector and supports USB 3.0.
> >> However it relies on usb-conn-gpio driver to read the vbus and id
> >> gpio's and provide role switch. However the driver currently has
> >> only gpio-b-connector compatible present in ID table. Adding that
> >> in DT would mean that the device supports Type-B connector and not
> >> Type-c connector. Thanks to Dmitry Baryshkov for pointing it out [2].
> >
> > USB-B connector is pretty simple, it really has just an ID pin and
> > VBUS input, which translates to two GPIOs being routed from the
> > _connector_ itself.
> >
> > USB-C is much more complicated, it has two CC pins and a VBus power
> > pin. It is not enough just to measure CC pin levels. Moreover,
> > properly handling USB 3.0 inside a USB-C connector requires a separate
> > 'orientation' signal to tell the host which two lanes must be used for
> > the USB SS signals. Thus it is no longer possible to route just two
> > pins from the connector to the SoC.
> >
> > Having all that in mind, I suspect that you are not describing your
> > hardware properly. I suppose that you have a Type-C port controller /
> > redriver / switch, which handles CC lines communication and then
> > provides ID / VBUS signals to the host. In such a case, please
> > describe this TCPC in the DT file and use its compatible string
> > instead of "gpio-c-connector".
> >
>
> Hi Dmitry,
>
>   My bad. I must have provided more details of the HW.
>
>   I presume you are referring to addition of a connector node, type-c
> switch, pmic-glink and other remote endpoints like in other SoC's like
> SM8450/ SM8550/ SM8650.
>
>   This HW is slightly different. It has a Uni Phy for Super speed and
> hence no DP.

This is fine and it's irrelevant for the USB-C.

>   For orientation switching, on mobile SoC's, there is a provision for
> orientation gpio given in pmic-glink node and is handled in ucsi_glink
> driver. But on this version of HW, there is a USB-C Switch with its own
> firmware taking care of orientation switching. It takes 8 SS Lines and 2
> CC lines coming from connector as input and gives out 4 SS Lines (SS
> TX1/TX2 RX1/RX2) as output which go to the SoC. So orientation switch is
> done by the USB-C-switch in between and it automatically routes
> appropriate active SS Lane from connector to the SoC.

This is also fine. As I wrote, you _have_ the Type-C port controller.
So your DT file should be describing your hardware.

>   As usual like in other targets, the DP and DM lines from type-c
> connector go to the SoC directly.
>
>   To handle role switch, the VBUS and ID Pin connections are given to
> SoC as well. There is a vbus controller regulator present to provide
> vbus to connected peripherals in host mode.
>
>   There is no PPM entity (ADSP in mobile SoC's) and no UCSI involved
> here. Hence we rely on usb-conn-gpio to read the vbus/id and switch
> roles accordingly.

This is also fine.

You confirmed my suspicions. You have an external Type-C switch which
handles orientation (and most likely PD or non-PD power negotiation)
for you. It has GPIO outputs, etc.

But it is not a part of the connector. Instead of adding the
"gpio-usb-c-connector", add proper compatible string (see, how this is
handled e.g. by the spidev - it is a generic driver, but it requires
hardware-specific compatibles).
Your hardware description should look like:

typec {
    compatible = "your,switch";
    id-gpios = <&gpio 1>;
    vbus-gpios = <&gpio 2>;
    vbus-supplies = <&reg-vbus>;

    ports {
       #address-cells = <1>;
       #size-cells = <1>;
       port@0 {
          endpoint {
              remote-endpoint = <&usb_dwc3_hs_out>;
          };
       };
       port@1 {
          endpoint {
              remote-endpoint = <&usb_uni_phy_out>;
          };
      };
      /* No SBU port */
   };
};

Note, I haven't said anything regarding the driver. You can continue
using the usb-conn-gpio driver. Just add a compatible string for you
switch.

>
>   Hope this answers the query as to why we wanted to use usb-conn-gpio
> and why we were trying to add a new compatible.
>
> Regards,
> Krishna,
>
> >>
> >> This series intends to add that compatible in driver and bindings
> >> so that it can be used in QDU1000 IDP DT.
> >>
> >> [1]: https://lore.kernel.org/all/20240319091020.15137-3-quic_kbajaj@quicinc.com/
> >> [2]: https://lore.kernel.org/all/CAA8EJprXPvji8TgZu1idH7y4GtHtD4VmQABFBcRt-9BQaCberg@mail.gmail.com/
> >>
> >> Krishna Kurapati (2):
> >>    dt-bindings: connector: Add gpio-usb-c-connector compatible
> >>    usb: common: usb-conn-gpio: Update ID table to add usb-c connector
> >>
> >>   Documentation/devicetree/bindings/connector/usb-connector.yaml | 3 +++
> >>   drivers/usb/common/usb-conn-gpio.c                             | 1 +
> >>   2 files changed, 4 insertions(+)
> >>
> >> --
> >> 2.34.1
> >>
> >
> >
> > --
> > With best wishes
> > Dmitry



-- 
With best wishes
Dmitry

^ permalink raw reply

* [PATCH v2 3/3] arm64: dts: freescale: Add device tree for Emcraft Systems NavQ+ Kit
From: Gilles Talis @ 2024-03-30 13:34 UTC (permalink / raw)
  To: devicetree, imx, linux-arm-kernel
  Cc: conor+dt, krzysztof.kozlowski+dt, robh, shawnguo, festevam, alex,
	andrew, Gilles Talis
In-Reply-To: <20240330133410.41408-1-gilles.talis@gmail.com>

The Emcraft Systems NavQ+ kit is a mobile robotics platform
based on NXP i.MX8 MPlus SoC.

The following interfaces and devices are enabled:
- eMMC
- Gigabit Ethernet
- RTC
- SD-Card
- UART console

Signed-off-by: Gilles Talis <gilles.talis@gmail.com>
---
 arch/arm64/boot/dts/freescale/Makefile        |   1 +
 .../arm64/boot/dts/freescale/imx8mp-navqp.dts | 424 ++++++++++++++++++
 2 files changed, 425 insertions(+)
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-navqp.dts

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index 045250d0a040..bf99864c0bc4 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -166,6 +166,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-dhcom-pdk3.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-icore-mx8mp-edimm2.2.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-msc-sm2s-ep1.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-navqp.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-rdk.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-skov-revb-hdmi.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mp-skov-revb-lt6.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts b/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts
new file mode 100644
index 000000000000..5fd1614982cd
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx8mp-navqp.dts
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright 2021 Emcraft Systems
+ * Copyright 2024 Gilles Talis <gilles.talis@gmail.com>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+#include "imx8mp.dtsi"
+
+/ {
+	model = "Emcraft Systems i.MX8MPlus NavQ+ Kit";
+	compatible = "emcraft,imx8mp-navqp", "fsl,imx8mp";
+
+	chosen {
+		stdout-path = &uart2;
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_gpio_led>;
+
+		led-0 {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>;
+			default-state = "on";
+		};
+	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2 {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		regulator-name = "VSD_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+		startup-delay-us = <100>;
+		off-on-delay-us = <12000>;
+	};
+};
+
+&A53_0 {
+	cpu-supply = <&buck2>;
+};
+
+&A53_1 {
+	cpu-supply = <&buck2>;
+};
+
+&A53_2 {
+	cpu-supply = <&buck2>;
+};
+
+&A53_3 {
+	cpu-supply = <&buck2>;
+};
+
+&eqos {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_eqos>;
+	phy-mode = "rgmii-id";
+	phy-handle = <&ethphy0>;
+	status = "okay";
+
+	mdio {
+		compatible = "snps,dwmac-mdio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ethphy0: ethernet-phy@0 {
+			compatible = "ethernet-phy-ieee802.3-c22";
+			reg = <0>;
+			reset-gpios = <&gpio4 22 GPIO_ACTIVE_LOW>;
+			reset-assert-us = <1000>;
+			reset-deassert-us = <10000>;
+			qca,disable-smarteee;
+			qca,disable-hibernation-mode;
+		};
+	};
+};
+
+&i2c1 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	status = "okay";
+
+	pmic@25 {
+		compatible = "nxp,pca9450c";
+		reg = <0x25>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pmic>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+
+		regulators {
+			BUCK1 {
+				regulator-name = "BUCK1";
+				regulator-min-microvolt = <600000>;
+				regulator-max-microvolt = <2187500>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <3125>;
+			};
+
+			buck2: BUCK2 {
+				regulator-name = "BUCK2";
+				regulator-min-microvolt = <600000>;
+				regulator-max-microvolt = <2187500>;
+				regulator-boot-on;
+				regulator-always-on;
+				regulator-ramp-delay = <3125>;
+				nxp,dvs-run-voltage = <950000>;
+				nxp,dvs-standby-voltage = <850000>;
+			};
+
+			BUCK4 {
+				regulator-name = "BUCK4";
+				regulator-min-microvolt = <600000>;
+				regulator-max-microvolt = <3400000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			BUCK5 {
+				regulator-name = "BUCK5";
+				regulator-min-microvolt = <600000>;
+				regulator-max-microvolt = <3400000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			BUCK6 {
+				regulator-name = "BUCK6";
+				regulator-min-microvolt = <600000>;
+				regulator-max-microvolt = <3400000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			LDO1 {
+				regulator-name = "LDO1";
+				regulator-min-microvolt = <1600000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			LDO2 {
+				regulator-name = "LDO2";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <1150000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			LDO3 {
+				regulator-name = "LDO3";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			LDO4 {
+				regulator-name = "LDO4";
+				regulator-min-microvolt = <800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+
+			LDO5 {
+				regulator-name = "LDO5";
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-boot-on;
+				regulator-always-on;
+			};
+		};
+	};
+};
+
+&i2c2 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+};
+
+&i2c3 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+	status = "okay";
+};
+
+&i2c4 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c4>;
+	status = "okay";
+
+	rtc@53 {
+		compatible = "nxp,pcf2131";
+		reg = <0x53>;
+	};
+};
+
+&uart2 {
+	/* console */
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2>;
+	status = "okay";
+};
+
+/* SD Card */
+&usdhc2 {
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	bus-width = <4>;
+	status = "okay";
+};
+
+/* eMMC */
+&usdhc3 {
+	assigned-clocks = <&clk IMX8MP_CLK_USDHC3>;
+	assigned-clock-rates = <400000000>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc3>;
+	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+	bus-width = <8>;
+	non-removable;
+	status = "okay";
+};
+
+&wdog1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_wdog>;
+	fsl,ext-reset-output;
+	status = "okay";
+};
+
+&iomuxc {
+	pinctrl_eqos: eqosgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC				0x3
+			MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO				0x3
+			MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0			0x91
+			MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1			0x91
+			MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2			0x91
+			MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3			0x91
+			MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK	0x91
+			MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL			0x91
+			MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0			0x1f
+			MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1			0x1f
+			MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2			0x1f
+			MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3			0x1f
+			MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL			0x1f
+			MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK	0x1f
+			MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22				0x110
+		>;
+	};
+
+	pinctrl_gpio_led: gpioledgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16				0x19
+		>;
+	};
+
+	pinctrl_i2c1: i2c1grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL					0x400001c3
+			MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA					0x400001c3
+		>;
+	};
+
+	pinctrl_i2c2: i2c2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL					0x400001c3
+			MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA					0x400001c3
+		>;
+	};
+
+	pinctrl_i2c3: i2c3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL					0x400001c3
+			MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA					0x400001c3
+		>;
+	};
+
+	pinctrl_i2c4: i2c4grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_I2C4_SCL__I2C4_SCL					0x400001c3
+			MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA					0x400001c3
+		>;
+	};
+
+	pinctrl_pmic: pmicgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03				0x41
+		>;
+	};
+
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19				0x41
+		>;
+	};
+
+	pinctrl_uart2: uart2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX				0x49
+			MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX				0x49
+		>;
+	};
+
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK				0x190
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD				0x1d0
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0				0x1d0
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1				0x1d0
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2				0x1d0
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3				0x1d0
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT				0xc1
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK				0x194
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD				0x1d4
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0				0x1d4
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1				0x1d4
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2				0x1d4
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3				0x1d4
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT				0xc1
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK				0x196
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD				0x1d6
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0				0x1d6
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1				0x1d6
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2				0x1d6
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3				0x1d6
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT				0xc1
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12				0x1c4
+		>;
+	};
+
+	pinctrl_usdhc3: usdhc3grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK				0x190
+			MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD				0x1d0
+			MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0				0x1d0
+			MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1				0x1d0
+			MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2				0x1d0
+			MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3				0x1d0
+			MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4				0x1d0
+			MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5				0x1d0
+			MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6				0x1d0
+			MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7				0x1d0
+			MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE				0x190
+		>;
+	};
+
+	pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK				0x194
+			MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD				0x1d4
+			MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0				0x1d4
+			MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1				0x1d4
+			MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2				0x1d4
+			MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3				0x1d4
+			MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4				0x1d4
+			MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5				0x1d4
+			MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6				0x1d4
+			MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7				0x1d4
+			MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE				0x194
+		>;
+	};
+
+	pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK				0x196
+			MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD				0x1d6
+			MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0				0x1d6
+			MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1				0x1d6
+			MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2				0x1d6
+			MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3				0x1d6
+			MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4				0x1d6
+			MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5				0x1d6
+			MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6				0x1d6
+			MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7				0x1d6
+			MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE				0x196
+		>;
+	};
+
+	pinctrl_wdog: wdoggrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B				0xc6
+		>;
+	};
+};
-- 
2.39.2


^ permalink raw reply related

* [PATCH v2 2/3] dt-bindings: arm: Add Emcraft Systems i.MX8M Plus NavQ+ Kit
From: Gilles Talis @ 2024-03-30 13:34 UTC (permalink / raw)
  To: devicetree, imx, linux-arm-kernel
  Cc: conor+dt, krzysztof.kozlowski+dt, robh, shawnguo, festevam, alex,
	andrew, Gilles Talis, Krzysztof Kozlowski
In-Reply-To: <20240330133410.41408-1-gilles.talis@gmail.com>

Add DT compatible string for Emcraft NavQ+ kit based on
the i.MX8M Plus SoC from NXP

Signed-off-by: Gilles Talis <gilles.talis@gmail.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 0027201e19f8..cec1b31d0792 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1050,6 +1050,7 @@ properties:
           - enum:
               - beacon,imx8mp-beacon-kit  # i.MX8MP Beacon Development Kit
               - dmo,imx8mp-data-modul-edm-sbc # i.MX8MP eDM SBC
+              - emcraft,imx8mp-navqp      # i.MX8MP Emcraft Systems NavQ+ Kit
               - fsl,imx8mp-evk            # i.MX8MP EVK Board
               - gateworks,imx8mp-gw71xx-2x # i.MX8MP Gateworks Board
               - gateworks,imx8mp-gw72xx-2x # i.MX8MP Gateworks Board
-- 
2.39.2


^ permalink raw reply related

* [PATCH v2 1/3] dt-bindings: vendor-prefixes: Add Emcraft Systems
From: Gilles Talis @ 2024-03-30 13:34 UTC (permalink / raw)
  To: devicetree, imx, linux-arm-kernel
  Cc: conor+dt, krzysztof.kozlowski+dt, robh, shawnguo, festevam, alex,
	andrew, Gilles Talis, Krzysztof Kozlowski
In-Reply-To: <20240330133410.41408-1-gilles.talis@gmail.com>

Add an entry for Emcraft Systems (https://www.emcraft.com/)

Signed-off-by: Gilles Talis <gilles.talis@gmail.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index b97d298b3eb6..8b978c6f1dfd 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -438,6 +438,8 @@ patternProperties:
     description: Dongguan EmbedFire Electronic Technology Co., Ltd.
   "^embest,.*":
     description: Shenzhen Embest Technology Co., Ltd.
+  "^emcraft,.*":
+    description: Emcraft Systems
   "^emlid,.*":
     description: Emlid, Ltd.
   "^emmicro,.*":
-- 
2.39.2


^ permalink raw reply related

* [PATCH v2 0/3] Add support for Emcraft Systems NavQ+ kit
From: Gilles Talis @ 2024-03-30 13:34 UTC (permalink / raw)
  To: devicetree, imx, linux-arm-kernel
  Cc: conor+dt, krzysztof.kozlowski+dt, robh, shawnguo, festevam, alex,
	andrew, Gilles Talis

Hello

This series adds a device tree file for the Emcraft Systems NavQ+ kit [1]

The first patch adds a new vendor prefix for Emcraft Systems
The second one adds the board to the arm/fsl.yaml DT bindings.
Last patch adds device tree file for the kit.

[1] https://www.emcraft.com/products/1222

Changes in v2:
- Add Acked-by review tags
- Fixed device tree warnings reported by dtbs_check
- Reworked leds node
- Remove unused i2c6 pinctrl entry
- Removed unused regulator node in Ethernet entry
- Link to v1: https://lore.kernel.org/imx/20240328202320.187596-1-gilles.talis@gmail.com/
---
Gilles Talis (3):
  dt-bindings: vendor-prefixes: Add Emcraft Systems
  dt-bindings: arm: Add Emcraft Systems i.MX8M Plus NavQ+ Kit
  arm64: dts: freescale: Add device tree for Emcraft Systems NavQ+ Kit

 .../devicetree/bindings/arm/fsl.yaml          |   1 +
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 arch/arm64/boot/dts/freescale/Makefile        |   1 +
 .../arm64/boot/dts/freescale/imx8mp-navqp.dts | 424 ++++++++++++++++++
 4 files changed, 428 insertions(+)
 create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-navqp.dts


base-commit: 4cece764965020c22cff7665b18a012006359095
-- 
2.39.2


^ 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