mbox series

[v6,0/7] PCI: amlogic: Make PCIe working reliably on AXG platforms

Message ID 20200123232943.10229-1-repk@triplefau.lt
Headers show
Series PCI: amlogic: Make PCIe working reliably on AXG platforms | expand

Message

Remi Pommarel Jan. 23, 2020, 11:29 p.m. UTC
PCIe device probing failures have been seen on AXG platforms and were
due to unreliable clock signal output. Setting HHI_MIPI_CNTL0[26] bit
in MIPI's PHY registers solved the problem. This bit controls band gap
reference.

As discussed here [1] one of these shared MIPI/PCIE analog PHY register
bits was implemented in the clock driver as CLKID_MIPI_ENABLE. This adds
a PHY driver to control this bit instead, as well as setting the band
gap one in order to get reliable PCIE communication.

While at it add another PHY driver to control PCIE only PHY registers,
making AXG code more similar to G12A platform thus allowing to remove
some specific platform handling in pci-meson driver.

Please note that CLKID_MIPI_ENABLE removable will be done in a different
serie.

Changes since v5:
 - Add additionalProperties in device tree binding documentation
 - Make analog PHY required

Changes since v4:
 - Rename the shared MIPI/PCIe PHY to analog
 - Chain the MIPI/PCIe PHY to the PCIe one

Changes since v3:
 - Go back to the shared MIPI/PCIe phy driver solution from v2
 - Remove syscon usage
 - Add all dt-bindings documentation

Changes since v2:
 - Remove shared MIPI/PCIE device driver and use syscon to access register
   in PCIE only driver instead
 - Include devicetree documentation

Changes sinve v1:
 - Move HHI_MIPI_CNTL0 bit control in its own PHY driver
 - Add a PHY driver for PCIE_PHY registers
 - Modify pci-meson.c to make use of both PHYs and remove specific
   handling for AXG and G12A

[1] https://lkml.org/lkml/2019/12/16/119

Remi Pommarel (7):
  dt-bindings: Add AXG PCIE PHY bindings
  dt-bindings: Add AXG shared MIPI/PCIE analog PHY bindings
  dt-bindings: PCI: meson: Update PCIE bindings documentation
  arm64: dts: meson-axg: Add PCIE PHY nodes
  phy: amlogic: Add Amlogic AXG MIPI/PCIE analog PHY Driver
  phy: amlogic: Add Amlogic AXG PCIE PHY Driver
  PCI: amlogic: Use AXG PCIE

 .../bindings/pci/amlogic,meson-pcie.txt       |  22 +-
 .../amlogic,meson-axg-mipi-pcie-analog.yaml   |  35 ++++
 .../bindings/phy/amlogic,meson-axg-pcie.yaml  |  52 +++++
 arch/arm64/boot/dts/amlogic/meson-axg.dtsi    |  16 ++
 drivers/pci/controller/dwc/pci-meson.c        | 116 ++---------
 drivers/phy/amlogic/Kconfig                   |  22 ++
 drivers/phy/amlogic/Makefile                  |  12 +-
 .../amlogic/phy-meson-axg-mipi-pcie-analog.c  | 188 +++++++++++++++++
 drivers/phy/amlogic/phy-meson-axg-pcie.c      | 192 ++++++++++++++++++
 9 files changed, 543 insertions(+), 112 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
 create mode 100644 Documentation/devicetree/bindings/phy/amlogic,meson-axg-pcie.yaml
 create mode 100644 drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
 create mode 100644 drivers/phy/amlogic/phy-meson-axg-pcie.c

Comments

Neil Armstrong Jan. 24, 2020, 8:02 a.m. UTC | #1
Hi,

On 24/01/2020 00:29, Remi Pommarel wrote:
> PCIe device probing failures have been seen on AXG platforms and were
> due to unreliable clock signal output. Setting HHI_MIPI_CNTL0[26] bit
> in MIPI's PHY registers solved the problem. This bit controls band gap
> reference.
> 
> As discussed here [1] one of these shared MIPI/PCIE analog PHY register
> bits was implemented in the clock driver as CLKID_MIPI_ENABLE. This adds
> a PHY driver to control this bit instead, as well as setting the band
> gap one in order to get reliable PCIE communication.
> 
> While at it add another PHY driver to control PCIE only PHY registers,
> making AXG code more similar to G12A platform thus allowing to remove
> some specific platform handling in pci-meson driver.
> 
> Please note that CLKID_MIPI_ENABLE removable will be done in a different
> serie.
> 
> Changes since v5:
>  - Add additionalProperties in device tree binding documentation
>  - Make analog PHY required
> 
> Changes since v4:
>  - Rename the shared MIPI/PCIe PHY to analog
>  - Chain the MIPI/PCIe PHY to the PCIe one
> 
> Changes since v3:
>  - Go back to the shared MIPI/PCIe phy driver solution from v2
>  - Remove syscon usage
>  - Add all dt-bindings documentation
> 
> Changes since v2:
>  - Remove shared MIPI/PCIE device driver and use syscon to access register
>    in PCIE only driver instead
>  - Include devicetree documentation
> 
> Changes sinve v1:
>  - Move HHI_MIPI_CNTL0 bit control in its own PHY driver
>  - Add a PHY driver for PCIE_PHY registers
>  - Modify pci-meson.c to make use of both PHYs and remove specific
>    handling for AXG and G12A
> 
> [1] https://lkml.org/lkml/2019/12/16/119
> 
> Remi Pommarel (7):
>   dt-bindings: Add AXG PCIE PHY bindings
>   dt-bindings: Add AXG shared MIPI/PCIE analog PHY bindings
>   dt-bindings: PCI: meson: Update PCIE bindings documentation
>   arm64: dts: meson-axg: Add PCIE PHY nodes
>   phy: amlogic: Add Amlogic AXG MIPI/PCIE analog PHY Driver
>   phy: amlogic: Add Amlogic AXG PCIE PHY Driver
>   PCI: amlogic: Use AXG PCIE
> 
>  .../bindings/pci/amlogic,meson-pcie.txt       |  22 +-
>  .../amlogic,meson-axg-mipi-pcie-analog.yaml   |  35 ++++
>  .../bindings/phy/amlogic,meson-axg-pcie.yaml  |  52 +++++
>  arch/arm64/boot/dts/amlogic/meson-axg.dtsi    |  16 ++
>  drivers/pci/controller/dwc/pci-meson.c        | 116 ++---------
>  drivers/phy/amlogic/Kconfig                   |  22 ++
>  drivers/phy/amlogic/Makefile                  |  12 +-
>  .../amlogic/phy-meson-axg-mipi-pcie-analog.c  | 188 +++++++++++++++++
>  drivers/phy/amlogic/phy-meson-axg-pcie.c      | 192 ++++++++++++++++++
>  9 files changed, 543 insertions(+), 112 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
>  create mode 100644 Documentation/devicetree/bindings/phy/amlogic,meson-axg-pcie.yaml
>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-pcie.c
> 

You forgot to keep the Reviewed-by/Acked-by tags from the previous reviews.

Neil
Remi Pommarel Jan. 24, 2020, 8:32 a.m. UTC | #2
Add missing Reviewed/Acked-by from v5.

On Fri, Jan 24, 2020 at 12:29:41AM +0100, Remi Pommarel wrote:
> This adds support for the MIPI analog PHY which is also used for PCIE
> found in the Amlogic AXG SoC Family.
> 
> MIPI or PCIE selection is done by the #phy-cells, making the mode
> static and exclusive.
> 
> For now only PCIE fonctionality is supported.
> 
> This PHY will be used to replace the mipi_enable clock gating logic
> which was mistakenly added in the clock subsystem. This also activate
> a non documented band gap bit in those registers that allows reliable
> PCIE clock signal generation on AXG platforms.

Acked-by: Jerome Brunet <jbrunet@baylibre.com>

> 
> Signed-off-by: Remi Pommarel <repk@triplefau.lt>
> ---
>  drivers/phy/amlogic/Kconfig                   |  11 +
>  drivers/phy/amlogic/Makefile                  |  11 +-
>  .../amlogic/phy-meson-axg-mipi-pcie-analog.c  | 188 ++++++++++++++++++
>  3 files changed, 205 insertions(+), 5 deletions(-)
>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> 
> diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig
> index af774ac2b934..8c9cf2403591 100644
> --- a/drivers/phy/amlogic/Kconfig
> +++ b/drivers/phy/amlogic/Kconfig
> @@ -59,3 +59,14 @@ config PHY_MESON_G12A_USB3_PCIE
>  	  Enable this to support the Meson USB3 + PCIE Combo PHY found
>  	  in Meson G12A SoCs.
>  	  If unsure, say N.
> +
> +config PHY_MESON_AXG_MIPI_PCIE_ANALOG
> +	tristate "Meson AXG MIPI + PCIE analog PHY driver"
> +	default ARCH_MESON
> +	depends on OF && (ARCH_MESON || COMPILE_TEST)
> +	select GENERIC_PHY
> +	select REGMAP_MMIO
> +	help
> +	  Enable this to support the Meson MIPI + PCIE analog PHY
> +	  found in Meson AXG SoCs.
> +	  If unsure, say N.
> diff --git a/drivers/phy/amlogic/Makefile b/drivers/phy/amlogic/Makefile
> index 11d1c42ac2be..0aecf92d796a 100644
> --- a/drivers/phy/amlogic/Makefile
> +++ b/drivers/phy/amlogic/Makefile
> @@ -1,6 +1,7 @@
>  # SPDX-License-Identifier: GPL-2.0-only
> -obj-$(CONFIG_PHY_MESON8B_USB2)		+= phy-meson8b-usb2.o
> -obj-$(CONFIG_PHY_MESON_GXL_USB2)	+= phy-meson-gxl-usb2.o
> -obj-$(CONFIG_PHY_MESON_G12A_USB2)	+= phy-meson-g12a-usb2.o
> -obj-$(CONFIG_PHY_MESON_GXL_USB3)	+= phy-meson-gxl-usb3.o
> -obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE)	+= phy-meson-g12a-usb3-pcie.o
> +obj-$(CONFIG_PHY_MESON8B_USB2)			+= phy-meson8b-usb2.o
> +obj-$(CONFIG_PHY_MESON_GXL_USB2)		+= phy-meson-gxl-usb2.o
> +obj-$(CONFIG_PHY_MESON_G12A_USB2)		+= phy-meson-g12a-usb2.o
> +obj-$(CONFIG_PHY_MESON_GXL_USB3)		+= phy-meson-gxl-usb3.o
> +obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE)		+= phy-meson-g12a-usb3-pcie.o
> +obj-$(CONFIG_PHY_MESON_AXG_MIPI_PCIE_ANALOG)	+= phy-meson-axg-mipi-pcie-analog.o
> diff --git a/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> new file mode 100644
> index 000000000000..1431cbf885e1
> --- /dev/null
> +++ b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> @@ -0,0 +1,188 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Amlogic AXG MIPI + PCIE analog PHY driver
> + *
> + * Copyright (C) 2019 Remi Pommarel <repk@triplefau.lt>
> + */
> +#include <linux/module.h>
> +#include <linux/phy/phy.h>
> +#include <linux/regmap.h>
> +#include <linux/platform_device.h>
> +#include <dt-bindings/phy/phy.h>
> +
> +#define HHI_MIPI_CNTL0 0x00
> +#define		HHI_MIPI_CNTL0_COMMON_BLOCK	GENMASK(31, 28)
> +#define		HHI_MIPI_CNTL0_ENABLE		BIT(29)
> +#define		HHI_MIPI_CNTL0_BANDGAP		BIT(26)
> +#define		HHI_MIPI_CNTL0_DECODE_TO_RTERM	GENMASK(15, 12)
> +#define		HHI_MIPI_CNTL0_OUTPUT_EN	BIT(3)
> +
> +#define HHI_MIPI_CNTL1 0x01
> +#define		HHI_MIPI_CNTL1_CH0_CML_PDR_EN	BIT(12)
> +#define		HHI_MIPI_CNTL1_LP_ABILITY	GENMASK(5, 4)
> +#define		HHI_MIPI_CNTL1_LP_RESISTER	BIT(3)
> +#define		HHI_MIPI_CNTL1_INPUT_SETTING	BIT(2)
> +#define		HHI_MIPI_CNTL1_INPUT_SEL	BIT(1)
> +#define		HHI_MIPI_CNTL1_PRBS7_EN		BIT(0)
> +
> +#define HHI_MIPI_CNTL2 0x02
> +#define		HHI_MIPI_CNTL2_CH_PU		GENMASK(31, 25)
> +#define		HHI_MIPI_CNTL2_CH_CTL		GENMASK(24, 19)
> +#define		HHI_MIPI_CNTL2_CH0_DIGDR_EN	BIT(18)
> +#define		HHI_MIPI_CNTL2_CH_DIGDR_EN	BIT(17)
> +#define		HHI_MIPI_CNTL2_LPULPS_EN	BIT(16)
> +#define		HHI_MIPI_CNTL2_CH_EN(n)		BIT(15 - (n))
> +#define		HHI_MIPI_CNTL2_CH0_LP_CTL	GENMASK(10, 1)
> +
> +struct phy_axg_mipi_pcie_analog_priv {
> +	struct phy *phy;
> +	unsigned int mode;
> +	struct regmap *regmap;
> +};
> +
> +static const struct regmap_config phy_axg_mipi_pcie_analog_regmap_conf = {
> +	.reg_bits = 8,
> +	.val_bits = 32,
> +	.reg_stride = 4,
> +	.max_register = HHI_MIPI_CNTL2,
> +};
> +
> +static int phy_axg_mipi_pcie_analog_power_on(struct phy *phy)
> +{
> +	struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
> +
> +	/* MIPI not supported yet */
> +	if (priv->mode != PHY_TYPE_PCIE)
> +		return -EINVAL;
> +
> +	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> +			   HHI_MIPI_CNTL0_BANDGAP, HHI_MIPI_CNTL0_BANDGAP);
> +
> +	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> +			   HHI_MIPI_CNTL0_ENABLE, HHI_MIPI_CNTL0_ENABLE);
> +	return 0;
> +}
> +
> +static int phy_axg_mipi_pcie_analog_power_off(struct phy *phy)
> +{
> +	struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
> +
> +	/* MIPI not supported yet */
> +	if (priv->mode != PHY_TYPE_PCIE)
> +		return -EINVAL;
> +
> +	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> +			   HHI_MIPI_CNTL0_BANDGAP, 0);
> +	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> +			   HHI_MIPI_CNTL0_ENABLE, 0);
> +	return 0;
> +}
> +
> +static int phy_axg_mipi_pcie_analog_init(struct phy *phy)
> +{
> +	return 0;
> +}
> +
> +static int phy_axg_mipi_pcie_analog_exit(struct phy *phy)
> +{
> +	return 0;
> +}
> +
> +static const struct phy_ops phy_axg_mipi_pcie_analog_ops = {
> +	.init = phy_axg_mipi_pcie_analog_init,
> +	.exit = phy_axg_mipi_pcie_analog_exit,
> +	.power_on = phy_axg_mipi_pcie_analog_power_on,
> +	.power_off = phy_axg_mipi_pcie_analog_power_off,
> +	.owner = THIS_MODULE,
> +};
> +
> +static struct phy *phy_axg_mipi_pcie_analog_xlate(struct device *dev,
> +						  struct of_phandle_args *args)
> +{
> +	struct phy_axg_mipi_pcie_analog_priv *priv = dev_get_drvdata(dev);
> +	unsigned int mode;
> +
> +	if (args->args_count != 1) {
> +		dev_err(dev, "invalid number of arguments\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	mode = args->args[0];
> +
> +	/* MIPI mode is not supported yet */
> +	if (mode != PHY_TYPE_PCIE) {
> +		dev_err(dev, "invalid phy mode select argument\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	priv->mode = mode;
> +	return priv->phy;
> +}
> +
> +static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev)
> +{
> +	struct phy_provider *phy;
> +	struct device *dev = &pdev->dev;
> +	struct phy_axg_mipi_pcie_analog_priv *priv;
> +	struct device_node *np = dev->of_node;
> +	struct regmap *map;
> +	struct resource *res;
> +	void __iomem *base;
> +	int ret;
> +
> +	priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(base)) {
> +		dev_err(dev, "failed to get regmap base\n");
> +		return PTR_ERR(base);
> +	}
> +
> +	map = devm_regmap_init_mmio(dev, base,
> +				    &phy_axg_mipi_pcie_analog_regmap_conf);
> +	if (IS_ERR(map)) {
> +		dev_err(dev, "failed to get HHI regmap\n");
> +		return PTR_ERR(map);
> +	}
> +	priv->regmap = map;
> +
> +	priv->phy = devm_phy_create(dev, np, &phy_axg_mipi_pcie_analog_ops);
> +	if (IS_ERR(priv->phy)) {
> +		ret = PTR_ERR(priv->phy);
> +		if (ret != -EPROBE_DEFER)
> +			dev_err(dev, "failed to create PHY\n");
> +		return ret;
> +	}
> +
> +	phy_set_drvdata(priv->phy, priv);
> +	dev_set_drvdata(dev, priv);
> +
> +	phy = devm_of_phy_provider_register(dev,
> +					    phy_axg_mipi_pcie_analog_xlate);
> +
> +	return PTR_ERR_OR_ZERO(phy);
> +}
> +
> +static const struct of_device_id phy_axg_mipi_pcie_analog_of_match[] = {
> +	{
> +		.compatible = "amlogic,axg-mipi-pcie-analog-phy",
> +	},
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, phy_axg_mipi_pcie_analog_of_match);
> +
> +static struct platform_driver phy_axg_mipi_pcie_analog_driver = {
> +	.probe = phy_axg_mipi_pcie_analog_probe,
> +	.driver = {
> +		.name = "phy-axg-mipi-pcie-analog",
> +		.of_match_table = phy_axg_mipi_pcie_analog_of_match,
> +	},
> +};
> +module_platform_driver(phy_axg_mipi_pcie_analog_driver);
> +
> +MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>");
> +MODULE_DESCRIPTION("Amlogic AXG MIPI + PCIE analog PHY driver");
> +MODULE_LICENSE("GPL v2");
> -- 
> 2.24.1
>
Remi Pommarel Jan. 24, 2020, 8:34 a.m. UTC | #3
Add missing Reviewed/Acked-by from v5.

On Fri, Jan 24, 2020 at 12:29:40AM +0100, Remi Pommarel wrote:
> Enable both PCIE and shared MIPI/PCIE PHY nodes in order to make PCIE
> reliable on AXG SoC.
> 
> Signed-off-by: Remi Pommarel <repk@triplefau.lt>
> ---
>  arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
> index 04803c3bccfa..08a178aa0133 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
> @@ -12,6 +12,7 @@
>  #include <dt-bindings/interrupt-controller/arm-gic.h>
>  #include <dt-bindings/reset/amlogic,meson-axg-audio-arb.h>
>  #include <dt-bindings/reset/amlogic,meson-axg-reset.h>
> +#include <dt-bindings/phy/phy.h>
>  
>  / {
>  	compatible = "amlogic,meson-axg";
> @@ -1104,6 +1105,12 @@ hiubus: bus@ff63c000 {
>  			#size-cells = <2>;
>  			ranges = <0x0 0x0 0x0 0xff63c000 0x0 0x1c00>;
>  
> +			mipi_analog_phy: phy@0 {
> +				compatible = "amlogic,axg-mipi-pcie-analog-phy";
> +				reg = <0x0 0x0 0x0 0xc>;
> +				#phy-cells = <1>;
> +			};
> +
>  			sysctrl: system-controller@0 {
>  				compatible = "amlogic,meson-axg-hhi-sysctrl",
>  					     "simple-mfd", "syscon";
> @@ -1356,6 +1363,15 @@ tdmout_c: audio-controller@580 {
>  			};
>  		};
>  
> +		pcie_phy: bus@ff644000 {
> +			compatible = "amlogic,axg-pcie-phy";
> +			reg = <0x0 0xff644000 0x0 0x1c>;
> +			resets = <&reset RESET_PCIE_PHY>;
> +			phys = <&mipi_analog_phy PHY_TYPE_PCIE>;
> +			phy-names = "analog";
> +			#phy-cells = <0>;
> +		};
> +
>  		aobus: bus@ff800000 {
>  			compatible = "simple-bus";
>  			reg = <0x0 0xff800000 0x0 0x100000>;

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
Remi Pommarel Jan. 24, 2020, 8:35 a.m. UTC | #4
Add missing Reviewed/Acked-by from v5

On Fri, Jan 24, 2020 at 12:29:43AM +0100, Remi Pommarel wrote:
> Now that PCIE PHY has been introduced for AXG, the whole has_shared_phy
> logic can be mutualized between AXG and G12A platforms.
> 
> This new PHY makes use of the shared MIPI/PCIE analog PHY found on AXG
> platforms, which need to be used in order to have reliable PCIE
> communications.
> 
> Signed-off-by: Remi Pommarel <repk@triplefau.lt>
> ---
>  drivers/pci/controller/dwc/pci-meson.c | 116 +++++--------------------
>  1 file changed, 22 insertions(+), 94 deletions(-)
> 
> diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c
> index 3772b02a5c55..3715dceca1bf 100644
> --- a/drivers/pci/controller/dwc/pci-meson.c
> +++ b/drivers/pci/controller/dwc/pci-meson.c
> @@ -66,7 +66,6 @@
>  #define PORT_CLK_RATE			100000000UL
>  #define MAX_PAYLOAD_SIZE		256
>  #define MAX_READ_REQ_SIZE		256
> -#define MESON_PCIE_PHY_POWERUP		0x1c
>  #define PCIE_RESET_DELAY		500
>  #define PCIE_SHARED_RESET		1
>  #define PCIE_NORMAL_RESET		0
> @@ -81,26 +80,19 @@ enum pcie_data_rate {
>  struct meson_pcie_mem_res {
>  	void __iomem *elbi_base;
>  	void __iomem *cfg_base;
> -	void __iomem *phy_base;
>  };
>  
>  struct meson_pcie_clk_res {
>  	struct clk *clk;
> -	struct clk *mipi_gate;
>  	struct clk *port_clk;
>  	struct clk *general_clk;
>  };
>  
>  struct meson_pcie_rc_reset {
> -	struct reset_control *phy;
>  	struct reset_control *port;
>  	struct reset_control *apb;
>  };
>  
> -struct meson_pcie_param {
> -	bool has_shared_phy;
> -};
> -
>  struct meson_pcie {
>  	struct dw_pcie pci;
>  	struct meson_pcie_mem_res mem_res;
> @@ -108,7 +100,6 @@ struct meson_pcie {
>  	struct meson_pcie_rc_reset mrst;
>  	struct gpio_desc *reset_gpio;
>  	struct phy *phy;
> -	const struct meson_pcie_param *param;
>  };
>  
>  static struct reset_control *meson_pcie_get_reset(struct meson_pcie *mp,
> @@ -130,13 +121,6 @@ static int meson_pcie_get_resets(struct meson_pcie *mp)
>  {
>  	struct meson_pcie_rc_reset *mrst = &mp->mrst;
>  
> -	if (!mp->param->has_shared_phy) {
> -		mrst->phy = meson_pcie_get_reset(mp, "phy", PCIE_SHARED_RESET);
> -		if (IS_ERR(mrst->phy))
> -			return PTR_ERR(mrst->phy);
> -		reset_control_deassert(mrst->phy);
> -	}
> -
>  	mrst->port = meson_pcie_get_reset(mp, "port", PCIE_NORMAL_RESET);
>  	if (IS_ERR(mrst->port))
>  		return PTR_ERR(mrst->port);
> @@ -162,22 +146,6 @@ static void __iomem *meson_pcie_get_mem(struct platform_device *pdev,
>  	return devm_ioremap_resource(dev, res);
>  }
>  
> -static void __iomem *meson_pcie_get_mem_shared(struct platform_device *pdev,
> -					       struct meson_pcie *mp,
> -					       const char *id)
> -{
> -	struct device *dev = mp->pci.dev;
> -	struct resource *res;
> -
> -	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, id);
> -	if (!res) {
> -		dev_err(dev, "No REG resource %s\n", id);
> -		return ERR_PTR(-ENXIO);
> -	}
> -
> -	return devm_ioremap(dev, res->start, resource_size(res));
> -}
> -
>  static int meson_pcie_get_mems(struct platform_device *pdev,
>  			       struct meson_pcie *mp)
>  {
> @@ -189,14 +157,6 @@ static int meson_pcie_get_mems(struct platform_device *pdev,
>  	if (IS_ERR(mp->mem_res.cfg_base))
>  		return PTR_ERR(mp->mem_res.cfg_base);
>  
> -	/* Meson AXG SoC has two PCI controllers use same phy register */
> -	if (!mp->param->has_shared_phy) {
> -		mp->mem_res.phy_base =
> -			meson_pcie_get_mem_shared(pdev, mp, "phy");
> -		if (IS_ERR(mp->mem_res.phy_base))
> -			return PTR_ERR(mp->mem_res.phy_base);
> -	}
> -
>  	return 0;
>  }
>  
> @@ -204,37 +164,33 @@ static int meson_pcie_power_on(struct meson_pcie *mp)
>  {
>  	int ret = 0;
>  
> -	if (mp->param->has_shared_phy) {
> -		ret = phy_init(mp->phy);
> -		if (ret)
> -			return ret;
> +	ret = phy_init(mp->phy);
> +	if (ret)
> +		return ret;
>  
> -		ret = phy_power_on(mp->phy);
> -		if (ret) {
> -			phy_exit(mp->phy);
> -			return ret;
> -		}
> -	} else
> -		writel(MESON_PCIE_PHY_POWERUP, mp->mem_res.phy_base);
> +	ret = phy_power_on(mp->phy);
> +	if (ret) {
> +		phy_exit(mp->phy);
> +		return ret;
> +	}
>  
>  	return 0;
>  }
>  
> +static void meson_pcie_power_off(struct meson_pcie *mp)
> +{
> +	phy_power_off(mp->phy);
> +	phy_exit(mp->phy);
> +}
> +
>  static int meson_pcie_reset(struct meson_pcie *mp)
>  {
>  	struct meson_pcie_rc_reset *mrst = &mp->mrst;
>  	int ret = 0;
>  
> -	if (mp->param->has_shared_phy) {
> -		ret = phy_reset(mp->phy);
> -		if (ret)
> -			return ret;
> -	} else {
> -		reset_control_assert(mrst->phy);
> -		udelay(PCIE_RESET_DELAY);
> -		reset_control_deassert(mrst->phy);
> -		udelay(PCIE_RESET_DELAY);
> -	}
> +	ret = phy_reset(mp->phy);
> +	if (ret)
> +		return ret;
>  
>  	reset_control_assert(mrst->port);
>  	reset_control_assert(mrst->apb);
> @@ -286,12 +242,6 @@ static int meson_pcie_probe_clocks(struct meson_pcie *mp)
>  	if (IS_ERR(res->port_clk))
>  		return PTR_ERR(res->port_clk);
>  
> -	if (!mp->param->has_shared_phy) {
> -		res->mipi_gate = meson_pcie_probe_clock(dev, "mipi", 0);
> -		if (IS_ERR(res->mipi_gate))
> -			return PTR_ERR(res->mipi_gate);
> -	}
> -
>  	res->general_clk = meson_pcie_probe_clock(dev, "general", 0);
>  	if (IS_ERR(res->general_clk))
>  		return PTR_ERR(res->general_clk);
> @@ -562,7 +512,6 @@ static const struct dw_pcie_ops dw_pcie_ops = {
>  
>  static int meson_pcie_probe(struct platform_device *pdev)
>  {
> -	const struct meson_pcie_param *match_data;
>  	struct device *dev = &pdev->dev;
>  	struct dw_pcie *pci;
>  	struct meson_pcie *mp;
> @@ -576,17 +525,10 @@ static int meson_pcie_probe(struct platform_device *pdev)
>  	pci->dev = dev;
>  	pci->ops = &dw_pcie_ops;
>  
> -	match_data = of_device_get_match_data(dev);
> -	if (!match_data) {
> -		dev_err(dev, "failed to get match data\n");
> -		return -ENODEV;
> -	}
> -	mp->param = match_data;
> -
> -	if (mp->param->has_shared_phy) {
> -		mp->phy = devm_phy_get(dev, "pcie");
> -		if (IS_ERR(mp->phy))
> -			return PTR_ERR(mp->phy);
> +	mp->phy = devm_phy_get(dev, "pcie");
> +	if (IS_ERR(mp->phy)) {
> +		dev_err(dev, "get phy failed, %ld\n", PTR_ERR(mp->phy));
> +		return PTR_ERR(mp->phy);
>  	}
>  
>  	mp->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
> @@ -636,30 +578,16 @@ static int meson_pcie_probe(struct platform_device *pdev)
>  	return 0;
>  
>  err_phy:
> -	if (mp->param->has_shared_phy) {
> -		phy_power_off(mp->phy);
> -		phy_exit(mp->phy);
> -	}
> -
> +	meson_pcie_power_off(mp);
>  	return ret;
>  }
>  
> -static struct meson_pcie_param meson_pcie_axg_param = {
> -	.has_shared_phy = false,
> -};
> -
> -static struct meson_pcie_param meson_pcie_g12a_param = {
> -	.has_shared_phy = true,
> -};
> -
>  static const struct of_device_id meson_pcie_of_match[] = {
>  	{
>  		.compatible = "amlogic,axg-pcie",
> -		.data = &meson_pcie_axg_param,
>  	},
>  	{
>  		.compatible = "amlogic,g12a-pcie",
> -		.data = &meson_pcie_g12a_param,
>  	},
>  	{},
>  };

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
Remi Pommarel Jan. 24, 2020, 8:37 a.m. UTC | #5
Hi,

On Fri, Jan 24, 2020 at 09:02:12AM +0100, Neil Armstrong wrote:
> Hi,
> 
> On 24/01/2020 00:29, Remi Pommarel wrote:
> > PCIe device probing failures have been seen on AXG platforms and were
> > due to unreliable clock signal output. Setting HHI_MIPI_CNTL0[26] bit
> > in MIPI's PHY registers solved the problem. This bit controls band gap
> > reference.
> > 
> > As discussed here [1] one of these shared MIPI/PCIE analog PHY register
> > bits was implemented in the clock driver as CLKID_MIPI_ENABLE. This adds
> > a PHY driver to control this bit instead, as well as setting the band
> > gap one in order to get reliable PCIE communication.
> > 
> > While at it add another PHY driver to control PCIE only PHY registers,
> > making AXG code more similar to G12A platform thus allowing to remove
> > some specific platform handling in pci-meson driver.
> > 
> > Please note that CLKID_MIPI_ENABLE removable will be done in a different
> > serie.
> > 
> > Changes since v5:
> >  - Add additionalProperties in device tree binding documentation
> >  - Make analog PHY required
> > 
> > Changes since v4:
> >  - Rename the shared MIPI/PCIe PHY to analog
> >  - Chain the MIPI/PCIe PHY to the PCIe one
> > 
> > Changes since v3:
> >  - Go back to the shared MIPI/PCIe phy driver solution from v2
> >  - Remove syscon usage
> >  - Add all dt-bindings documentation
> > 
> > Changes since v2:
> >  - Remove shared MIPI/PCIE device driver and use syscon to access register
> >    in PCIE only driver instead
> >  - Include devicetree documentation
> > 
> > Changes sinve v1:
> >  - Move HHI_MIPI_CNTL0 bit control in its own PHY driver
> >  - Add a PHY driver for PCIE_PHY registers
> >  - Modify pci-meson.c to make use of both PHYs and remove specific
> >    handling for AXG and G12A
> > 
> > [1] https://lkml.org/lkml/2019/12/16/119
> > 
> > Remi Pommarel (7):
> >   dt-bindings: Add AXG PCIE PHY bindings
> >   dt-bindings: Add AXG shared MIPI/PCIE analog PHY bindings
> >   dt-bindings: PCI: meson: Update PCIE bindings documentation
> >   arm64: dts: meson-axg: Add PCIE PHY nodes
> >   phy: amlogic: Add Amlogic AXG MIPI/PCIE analog PHY Driver
> >   phy: amlogic: Add Amlogic AXG PCIE PHY Driver
> >   PCI: amlogic: Use AXG PCIE
> > 
> >  .../bindings/pci/amlogic,meson-pcie.txt       |  22 +-
> >  .../amlogic,meson-axg-mipi-pcie-analog.yaml   |  35 ++++
> >  .../bindings/phy/amlogic,meson-axg-pcie.yaml  |  52 +++++
> >  arch/arm64/boot/dts/amlogic/meson-axg.dtsi    |  16 ++
> >  drivers/pci/controller/dwc/pci-meson.c        | 116 ++---------
> >  drivers/phy/amlogic/Kconfig                   |  22 ++
> >  drivers/phy/amlogic/Makefile                  |  12 +-
> >  .../amlogic/phy-meson-axg-mipi-pcie-analog.c  | 188 +++++++++++++++++
> >  drivers/phy/amlogic/phy-meson-axg-pcie.c      | 192 ++++++++++++++++++
> >  9 files changed, 543 insertions(+), 112 deletions(-)
> >  create mode 100644 Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
> >  create mode 100644 Documentation/devicetree/bindings/phy/amlogic,meson-axg-pcie.yaml
> >  create mode 100644 drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> >  create mode 100644 drivers/phy/amlogic/phy-meson-axg-pcie.c
> > 
> 
> You forgot to keep the Reviewed-by/Acked-by tags from the previous reviews.
> 

Indeed, sorry about that, I have just added them.
Lorenzo Pieralisi Feb. 24, 2020, 2:15 p.m. UTC | #6
On Fri, Jan 24, 2020 at 12:29:36AM +0100, Remi Pommarel wrote:
> PCIe device probing failures have been seen on AXG platforms and were
> due to unreliable clock signal output. Setting HHI_MIPI_CNTL0[26] bit
> in MIPI's PHY registers solved the problem. This bit controls band gap
> reference.
> 
> As discussed here [1] one of these shared MIPI/PCIE analog PHY register
> bits was implemented in the clock driver as CLKID_MIPI_ENABLE. This adds
> a PHY driver to control this bit instead, as well as setting the band
> gap one in order to get reliable PCIE communication.
> 
> While at it add another PHY driver to control PCIE only PHY registers,
> making AXG code more similar to G12A platform thus allowing to remove
> some specific platform handling in pci-meson driver.
> 
> Please note that CLKID_MIPI_ENABLE removable will be done in a different
> serie.
> 
> Changes since v5:
>  - Add additionalProperties in device tree binding documentation
>  - Make analog PHY required
> 
> Changes since v4:
>  - Rename the shared MIPI/PCIe PHY to analog
>  - Chain the MIPI/PCIe PHY to the PCIe one
> 
> Changes since v3:
>  - Go back to the shared MIPI/PCIe phy driver solution from v2
>  - Remove syscon usage
>  - Add all dt-bindings documentation
> 
> Changes since v2:
>  - Remove shared MIPI/PCIE device driver and use syscon to access register
>    in PCIE only driver instead
>  - Include devicetree documentation
> 
> Changes sinve v1:
>  - Move HHI_MIPI_CNTL0 bit control in its own PHY driver
>  - Add a PHY driver for PCIE_PHY registers
>  - Modify pci-meson.c to make use of both PHYs and remove specific
>    handling for AXG and G12A
> 
> [1] https://lkml.org/lkml/2019/12/16/119
> 
> Remi Pommarel (7):
>   dt-bindings: Add AXG PCIE PHY bindings
>   dt-bindings: Add AXG shared MIPI/PCIE analog PHY bindings
>   dt-bindings: PCI: meson: Update PCIE bindings documentation
>   arm64: dts: meson-axg: Add PCIE PHY nodes
>   phy: amlogic: Add Amlogic AXG MIPI/PCIE analog PHY Driver
>   phy: amlogic: Add Amlogic AXG PCIE PHY Driver
>   PCI: amlogic: Use AXG PCIE
> 
>  .../bindings/pci/amlogic,meson-pcie.txt       |  22 +-
>  .../amlogic,meson-axg-mipi-pcie-analog.yaml   |  35 ++++
>  .../bindings/phy/amlogic,meson-axg-pcie.yaml  |  52 +++++
>  arch/arm64/boot/dts/amlogic/meson-axg.dtsi    |  16 ++
>  drivers/pci/controller/dwc/pci-meson.c        | 116 ++---------
>  drivers/phy/amlogic/Kconfig                   |  22 ++
>  drivers/phy/amlogic/Makefile                  |  12 +-
>  .../amlogic/phy-meson-axg-mipi-pcie-analog.c  | 188 +++++++++++++++++
>  drivers/phy/amlogic/phy-meson-axg-pcie.c      | 192 ++++++++++++++++++
>  9 files changed, 543 insertions(+), 112 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
>  create mode 100644 Documentation/devicetree/bindings/phy/amlogic,meson-axg-pcie.yaml
>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-pcie.c

Hi Remi,

I am ready to pull this series in, do you want me to ? Or you prefer
it to go via a different tree upstream ?

Thanks,
Lorenzo
Kevin Hilman Feb. 29, 2020, 4:07 p.m. UTC | #7
Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> writes:

> On Fri, Jan 24, 2020 at 12:29:36AM +0100, Remi Pommarel wrote:
>> PCIe device probing failures have been seen on AXG platforms and were
>> due to unreliable clock signal output. Setting HHI_MIPI_CNTL0[26] bit
>> in MIPI's PHY registers solved the problem. This bit controls band gap
>> reference.
>> 
>> As discussed here [1] one of these shared MIPI/PCIE analog PHY register
>> bits was implemented in the clock driver as CLKID_MIPI_ENABLE. This adds
>> a PHY driver to control this bit instead, as well as setting the band
>> gap one in order to get reliable PCIE communication.
>> 
>> While at it add another PHY driver to control PCIE only PHY registers,
>> making AXG code more similar to G12A platform thus allowing to remove
>> some specific platform handling in pci-meson driver.
>> 
>> Please note that CLKID_MIPI_ENABLE removable will be done in a different
>> serie.
>> 
>> Changes since v5:
>>  - Add additionalProperties in device tree binding documentation
>>  - Make analog PHY required
>> 
>> Changes since v4:
>>  - Rename the shared MIPI/PCIe PHY to analog
>>  - Chain the MIPI/PCIe PHY to the PCIe one
>> 
>> Changes since v3:
>>  - Go back to the shared MIPI/PCIe phy driver solution from v2
>>  - Remove syscon usage
>>  - Add all dt-bindings documentation
>> 
>> Changes since v2:
>>  - Remove shared MIPI/PCIE device driver and use syscon to access register
>>    in PCIE only driver instead
>>  - Include devicetree documentation
>> 
>> Changes sinve v1:
>>  - Move HHI_MIPI_CNTL0 bit control in its own PHY driver
>>  - Add a PHY driver for PCIE_PHY registers
>>  - Modify pci-meson.c to make use of both PHYs and remove specific
>>    handling for AXG and G12A
>> 
>> [1] https://lkml.org/lkml/2019/12/16/119
>> 
>> Remi Pommarel (7):
>>   dt-bindings: Add AXG PCIE PHY bindings
>>   dt-bindings: Add AXG shared MIPI/PCIE analog PHY bindings
>>   dt-bindings: PCI: meson: Update PCIE bindings documentation
>>   arm64: dts: meson-axg: Add PCIE PHY nodes
>>   phy: amlogic: Add Amlogic AXG MIPI/PCIE analog PHY Driver
>>   phy: amlogic: Add Amlogic AXG PCIE PHY Driver
>>   PCI: amlogic: Use AXG PCIE
>> 
>>  .../bindings/pci/amlogic,meson-pcie.txt       |  22 +-
>>  .../amlogic,meson-axg-mipi-pcie-analog.yaml   |  35 ++++
>>  .../bindings/phy/amlogic,meson-axg-pcie.yaml  |  52 +++++
>>  arch/arm64/boot/dts/amlogic/meson-axg.dtsi    |  16 ++
>>  drivers/pci/controller/dwc/pci-meson.c        | 116 ++---------
>>  drivers/phy/amlogic/Kconfig                   |  22 ++
>>  drivers/phy/amlogic/Makefile                  |  12 +-
>>  .../amlogic/phy-meson-axg-mipi-pcie-analog.c  | 188 +++++++++++++++++
>>  drivers/phy/amlogic/phy-meson-axg-pcie.c      | 192 ++++++++++++++++++
>>  9 files changed, 543 insertions(+), 112 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
>>  create mode 100644 Documentation/devicetree/bindings/phy/amlogic,meson-axg-pcie.yaml
>>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
>>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-pcie.c
>
> Hi Remi,
>
> I am ready to pull this series in, do you want me to ? Or you prefer
> it to go via a different tree upstream ?

To avoid conflicts, I'll take the DT patch (PATCH 4/7) through my
amlogic tree, but feel free to take the rest.

Kevin
Remi Pommarel Feb. 29, 2020, 5:10 p.m. UTC | #8
Hi

On Sat, Feb 29, 2020 at 05:07:43PM +0100, Kevin Hilman wrote:
> Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> writes:
> 
> > On Fri, Jan 24, 2020 at 12:29:36AM +0100, Remi Pommarel wrote:
> >> PCIe device probing failures have been seen on AXG platforms and were
> >> due to unreliable clock signal output. Setting HHI_MIPI_CNTL0[26] bit
> >> in MIPI's PHY registers solved the problem. This bit controls band gap
> >> reference.
> >> 
> >> As discussed here [1] one of these shared MIPI/PCIE analog PHY register
> >> bits was implemented in the clock driver as CLKID_MIPI_ENABLE. This adds
> >> a PHY driver to control this bit instead, as well as setting the band
> >> gap one in order to get reliable PCIE communication.
> >> 
> >> While at it add another PHY driver to control PCIE only PHY registers,
> >> making AXG code more similar to G12A platform thus allowing to remove
> >> some specific platform handling in pci-meson driver.
> >> 
> >> Please note that CLKID_MIPI_ENABLE removable will be done in a different
> >> serie.
> >> 
> >> Changes since v5:
> >>  - Add additionalProperties in device tree binding documentation
> >>  - Make analog PHY required
> >> 
> >> Changes since v4:
> >>  - Rename the shared MIPI/PCIe PHY to analog
> >>  - Chain the MIPI/PCIe PHY to the PCIe one
> >> 
> >> Changes since v3:
> >>  - Go back to the shared MIPI/PCIe phy driver solution from v2
> >>  - Remove syscon usage
> >>  - Add all dt-bindings documentation
> >> 
> >> Changes since v2:
> >>  - Remove shared MIPI/PCIE device driver and use syscon to access register
> >>    in PCIE only driver instead
> >>  - Include devicetree documentation
> >> 
> >> Changes sinve v1:
> >>  - Move HHI_MIPI_CNTL0 bit control in its own PHY driver
> >>  - Add a PHY driver for PCIE_PHY registers
> >>  - Modify pci-meson.c to make use of both PHYs and remove specific
> >>    handling for AXG and G12A
> >> 
> >> [1] https://lkml.org/lkml/2019/12/16/119
> >> 
> >> Remi Pommarel (7):
> >>   dt-bindings: Add AXG PCIE PHY bindings
> >>   dt-bindings: Add AXG shared MIPI/PCIE analog PHY bindings
> >>   dt-bindings: PCI: meson: Update PCIE bindings documentation
> >>   arm64: dts: meson-axg: Add PCIE PHY nodes
> >>   phy: amlogic: Add Amlogic AXG MIPI/PCIE analog PHY Driver
> >>   phy: amlogic: Add Amlogic AXG PCIE PHY Driver
> >>   PCI: amlogic: Use AXG PCIE
> >> 
> >>  .../bindings/pci/amlogic,meson-pcie.txt       |  22 +-
> >>  .../amlogic,meson-axg-mipi-pcie-analog.yaml   |  35 ++++
> >>  .../bindings/phy/amlogic,meson-axg-pcie.yaml  |  52 +++++
> >>  arch/arm64/boot/dts/amlogic/meson-axg.dtsi    |  16 ++
> >>  drivers/pci/controller/dwc/pci-meson.c        | 116 ++---------
> >>  drivers/phy/amlogic/Kconfig                   |  22 ++
> >>  drivers/phy/amlogic/Makefile                  |  12 +-
> >>  .../amlogic/phy-meson-axg-mipi-pcie-analog.c  | 188 +++++++++++++++++
> >>  drivers/phy/amlogic/phy-meson-axg-pcie.c      | 192 ++++++++++++++++++
> >>  9 files changed, 543 insertions(+), 112 deletions(-)
> >>  create mode 100644 Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
> >>  create mode 100644 Documentation/devicetree/bindings/phy/amlogic,meson-axg-pcie.yaml
> >>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> >>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-pcie.c
> >
> > Hi Remi,
> >
> > I am ready to pull this series in, do you want me to ? Or you prefer
> > it to go via a different tree upstream ?
> 
> To avoid conflicts, I'll take the DT patch (PATCH 4/7) through my
> amlogic tree, but feel free to take the rest.

Hi Lorenzo, Kevin,

The only issue I see here is that PATCH 6/7 does not have any
Reviewed-by/Acked-by, but if that is ok with you that will be nice to
have this upstream, thanks.

Sorry for the mail delivery error you could have received, silly me
forgot to renew the domain name.

Thanks

Remi
Lorenzo Pieralisi March 3, 2020, 3:03 p.m. UTC | #9
On Sat, Feb 29, 2020 at 05:07:43PM +0100, Kevin Hilman wrote:
> Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> writes:
> 
> > On Fri, Jan 24, 2020 at 12:29:36AM +0100, Remi Pommarel wrote:
> >> PCIe device probing failures have been seen on AXG platforms and were
> >> due to unreliable clock signal output. Setting HHI_MIPI_CNTL0[26] bit
> >> in MIPI's PHY registers solved the problem. This bit controls band gap
> >> reference.
> >> 
> >> As discussed here [1] one of these shared MIPI/PCIE analog PHY register
> >> bits was implemented in the clock driver as CLKID_MIPI_ENABLE. This adds
> >> a PHY driver to control this bit instead, as well as setting the band
> >> gap one in order to get reliable PCIE communication.
> >> 
> >> While at it add another PHY driver to control PCIE only PHY registers,
> >> making AXG code more similar to G12A platform thus allowing to remove
> >> some specific platform handling in pci-meson driver.
> >> 
> >> Please note that CLKID_MIPI_ENABLE removable will be done in a different
> >> serie.
> >> 
> >> Changes since v5:
> >>  - Add additionalProperties in device tree binding documentation
> >>  - Make analog PHY required
> >> 
> >> Changes since v4:
> >>  - Rename the shared MIPI/PCIe PHY to analog
> >>  - Chain the MIPI/PCIe PHY to the PCIe one
> >> 
> >> Changes since v3:
> >>  - Go back to the shared MIPI/PCIe phy driver solution from v2
> >>  - Remove syscon usage
> >>  - Add all dt-bindings documentation
> >> 
> >> Changes since v2:
> >>  - Remove shared MIPI/PCIE device driver and use syscon to access register
> >>    in PCIE only driver instead
> >>  - Include devicetree documentation
> >> 
> >> Changes sinve v1:
> >>  - Move HHI_MIPI_CNTL0 bit control in its own PHY driver
> >>  - Add a PHY driver for PCIE_PHY registers
> >>  - Modify pci-meson.c to make use of both PHYs and remove specific
> >>    handling for AXG and G12A
> >> 
> >> [1] https://lkml.org/lkml/2019/12/16/119
> >> 
> >> Remi Pommarel (7):
> >>   dt-bindings: Add AXG PCIE PHY bindings
> >>   dt-bindings: Add AXG shared MIPI/PCIE analog PHY bindings
> >>   dt-bindings: PCI: meson: Update PCIE bindings documentation
> >>   arm64: dts: meson-axg: Add PCIE PHY nodes
> >>   phy: amlogic: Add Amlogic AXG MIPI/PCIE analog PHY Driver
> >>   phy: amlogic: Add Amlogic AXG PCIE PHY Driver
> >>   PCI: amlogic: Use AXG PCIE
> >> 
> >>  .../bindings/pci/amlogic,meson-pcie.txt       |  22 +-
> >>  .../amlogic,meson-axg-mipi-pcie-analog.yaml   |  35 ++++
> >>  .../bindings/phy/amlogic,meson-axg-pcie.yaml  |  52 +++++
> >>  arch/arm64/boot/dts/amlogic/meson-axg.dtsi    |  16 ++
> >>  drivers/pci/controller/dwc/pci-meson.c        | 116 ++---------
> >>  drivers/phy/amlogic/Kconfig                   |  22 ++
> >>  drivers/phy/amlogic/Makefile                  |  12 +-
> >>  .../amlogic/phy-meson-axg-mipi-pcie-analog.c  | 188 +++++++++++++++++
> >>  drivers/phy/amlogic/phy-meson-axg-pcie.c      | 192 ++++++++++++++++++
> >>  9 files changed, 543 insertions(+), 112 deletions(-)
> >>  create mode 100644 Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
> >>  create mode 100644 Documentation/devicetree/bindings/phy/amlogic,meson-axg-pcie.yaml
> >>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> >>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-pcie.c
> >
> > Hi Remi,
> >
> > I am ready to pull this series in, do you want me to ? Or you prefer
> > it to go via a different tree upstream ?
> 
> To avoid conflicts, I'll take the DT patch (PATCH 4/7) through my
> amlogic tree, but feel free to take the rest.

That works for me Kevin, thanks !

Lorenzo
Lorenzo Pieralisi March 3, 2020, 5:19 p.m. UTC | #10
On Fri, Jan 24, 2020 at 12:29:41AM +0100, Remi Pommarel wrote:
> This adds support for the MIPI analog PHY which is also used for PCIE
> found in the Amlogic AXG SoC Family.
> 
> MIPI or PCIE selection is done by the #phy-cells, making the mode
> static and exclusive.
> 
> For now only PCIE fonctionality is supported.
> 
> This PHY will be used to replace the mipi_enable clock gating logic
> which was mistakenly added in the clock subsystem. This also activate
> a non documented band gap bit in those registers that allows reliable
> PCIE clock signal generation on AXG platforms.
> 
> Signed-off-by: Remi Pommarel <repk@triplefau.lt>
> ---
>  drivers/phy/amlogic/Kconfig                   |  11 +
>  drivers/phy/amlogic/Makefile                  |  11 +-
>  .../amlogic/phy-meson-axg-mipi-pcie-analog.c  | 188 ++++++++++++++++++
>  3 files changed, 205 insertions(+), 5 deletions(-)
>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c

Kishon, Neil,

can you please review/ack this patch and patch 6 ?

I would like to queue the series shortly, thanks.

Lorenzo

> diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig
> index af774ac2b934..8c9cf2403591 100644
> --- a/drivers/phy/amlogic/Kconfig
> +++ b/drivers/phy/amlogic/Kconfig
> @@ -59,3 +59,14 @@ config PHY_MESON_G12A_USB3_PCIE
>  	  Enable this to support the Meson USB3 + PCIE Combo PHY found
>  	  in Meson G12A SoCs.
>  	  If unsure, say N.
> +
> +config PHY_MESON_AXG_MIPI_PCIE_ANALOG
> +	tristate "Meson AXG MIPI + PCIE analog PHY driver"
> +	default ARCH_MESON
> +	depends on OF && (ARCH_MESON || COMPILE_TEST)
> +	select GENERIC_PHY
> +	select REGMAP_MMIO
> +	help
> +	  Enable this to support the Meson MIPI + PCIE analog PHY
> +	  found in Meson AXG SoCs.
> +	  If unsure, say N.
> diff --git a/drivers/phy/amlogic/Makefile b/drivers/phy/amlogic/Makefile
> index 11d1c42ac2be..0aecf92d796a 100644
> --- a/drivers/phy/amlogic/Makefile
> +++ b/drivers/phy/amlogic/Makefile
> @@ -1,6 +1,7 @@
>  # SPDX-License-Identifier: GPL-2.0-only
> -obj-$(CONFIG_PHY_MESON8B_USB2)		+= phy-meson8b-usb2.o
> -obj-$(CONFIG_PHY_MESON_GXL_USB2)	+= phy-meson-gxl-usb2.o
> -obj-$(CONFIG_PHY_MESON_G12A_USB2)	+= phy-meson-g12a-usb2.o
> -obj-$(CONFIG_PHY_MESON_GXL_USB3)	+= phy-meson-gxl-usb3.o
> -obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE)	+= phy-meson-g12a-usb3-pcie.o
> +obj-$(CONFIG_PHY_MESON8B_USB2)			+= phy-meson8b-usb2.o
> +obj-$(CONFIG_PHY_MESON_GXL_USB2)		+= phy-meson-gxl-usb2.o
> +obj-$(CONFIG_PHY_MESON_G12A_USB2)		+= phy-meson-g12a-usb2.o
> +obj-$(CONFIG_PHY_MESON_GXL_USB3)		+= phy-meson-gxl-usb3.o
> +obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE)		+= phy-meson-g12a-usb3-pcie.o
> +obj-$(CONFIG_PHY_MESON_AXG_MIPI_PCIE_ANALOG)	+= phy-meson-axg-mipi-pcie-analog.o
> diff --git a/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> new file mode 100644
> index 000000000000..1431cbf885e1
> --- /dev/null
> +++ b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> @@ -0,0 +1,188 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Amlogic AXG MIPI + PCIE analog PHY driver
> + *
> + * Copyright (C) 2019 Remi Pommarel <repk@triplefau.lt>
> + */
> +#include <linux/module.h>
> +#include <linux/phy/phy.h>
> +#include <linux/regmap.h>
> +#include <linux/platform_device.h>
> +#include <dt-bindings/phy/phy.h>
> +
> +#define HHI_MIPI_CNTL0 0x00
> +#define		HHI_MIPI_CNTL0_COMMON_BLOCK	GENMASK(31, 28)
> +#define		HHI_MIPI_CNTL0_ENABLE		BIT(29)
> +#define		HHI_MIPI_CNTL0_BANDGAP		BIT(26)
> +#define		HHI_MIPI_CNTL0_DECODE_TO_RTERM	GENMASK(15, 12)
> +#define		HHI_MIPI_CNTL0_OUTPUT_EN	BIT(3)
> +
> +#define HHI_MIPI_CNTL1 0x01
> +#define		HHI_MIPI_CNTL1_CH0_CML_PDR_EN	BIT(12)
> +#define		HHI_MIPI_CNTL1_LP_ABILITY	GENMASK(5, 4)
> +#define		HHI_MIPI_CNTL1_LP_RESISTER	BIT(3)
> +#define		HHI_MIPI_CNTL1_INPUT_SETTING	BIT(2)
> +#define		HHI_MIPI_CNTL1_INPUT_SEL	BIT(1)
> +#define		HHI_MIPI_CNTL1_PRBS7_EN		BIT(0)
> +
> +#define HHI_MIPI_CNTL2 0x02
> +#define		HHI_MIPI_CNTL2_CH_PU		GENMASK(31, 25)
> +#define		HHI_MIPI_CNTL2_CH_CTL		GENMASK(24, 19)
> +#define		HHI_MIPI_CNTL2_CH0_DIGDR_EN	BIT(18)
> +#define		HHI_MIPI_CNTL2_CH_DIGDR_EN	BIT(17)
> +#define		HHI_MIPI_CNTL2_LPULPS_EN	BIT(16)
> +#define		HHI_MIPI_CNTL2_CH_EN(n)		BIT(15 - (n))
> +#define		HHI_MIPI_CNTL2_CH0_LP_CTL	GENMASK(10, 1)
> +
> +struct phy_axg_mipi_pcie_analog_priv {
> +	struct phy *phy;
> +	unsigned int mode;
> +	struct regmap *regmap;
> +};
> +
> +static const struct regmap_config phy_axg_mipi_pcie_analog_regmap_conf = {
> +	.reg_bits = 8,
> +	.val_bits = 32,
> +	.reg_stride = 4,
> +	.max_register = HHI_MIPI_CNTL2,
> +};
> +
> +static int phy_axg_mipi_pcie_analog_power_on(struct phy *phy)
> +{
> +	struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
> +
> +	/* MIPI not supported yet */
> +	if (priv->mode != PHY_TYPE_PCIE)
> +		return -EINVAL;
> +
> +	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> +			   HHI_MIPI_CNTL0_BANDGAP, HHI_MIPI_CNTL0_BANDGAP);
> +
> +	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> +			   HHI_MIPI_CNTL0_ENABLE, HHI_MIPI_CNTL0_ENABLE);
> +	return 0;
> +}
> +
> +static int phy_axg_mipi_pcie_analog_power_off(struct phy *phy)
> +{
> +	struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
> +
> +	/* MIPI not supported yet */
> +	if (priv->mode != PHY_TYPE_PCIE)
> +		return -EINVAL;
> +
> +	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> +			   HHI_MIPI_CNTL0_BANDGAP, 0);
> +	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> +			   HHI_MIPI_CNTL0_ENABLE, 0);
> +	return 0;
> +}
> +
> +static int phy_axg_mipi_pcie_analog_init(struct phy *phy)
> +{
> +	return 0;
> +}
> +
> +static int phy_axg_mipi_pcie_analog_exit(struct phy *phy)
> +{
> +	return 0;
> +}
> +
> +static const struct phy_ops phy_axg_mipi_pcie_analog_ops = {
> +	.init = phy_axg_mipi_pcie_analog_init,
> +	.exit = phy_axg_mipi_pcie_analog_exit,
> +	.power_on = phy_axg_mipi_pcie_analog_power_on,
> +	.power_off = phy_axg_mipi_pcie_analog_power_off,
> +	.owner = THIS_MODULE,
> +};
> +
> +static struct phy *phy_axg_mipi_pcie_analog_xlate(struct device *dev,
> +						  struct of_phandle_args *args)
> +{
> +	struct phy_axg_mipi_pcie_analog_priv *priv = dev_get_drvdata(dev);
> +	unsigned int mode;
> +
> +	if (args->args_count != 1) {
> +		dev_err(dev, "invalid number of arguments\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	mode = args->args[0];
> +
> +	/* MIPI mode is not supported yet */
> +	if (mode != PHY_TYPE_PCIE) {
> +		dev_err(dev, "invalid phy mode select argument\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	priv->mode = mode;
> +	return priv->phy;
> +}
> +
> +static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev)
> +{
> +	struct phy_provider *phy;
> +	struct device *dev = &pdev->dev;
> +	struct phy_axg_mipi_pcie_analog_priv *priv;
> +	struct device_node *np = dev->of_node;
> +	struct regmap *map;
> +	struct resource *res;
> +	void __iomem *base;
> +	int ret;
> +
> +	priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(base)) {
> +		dev_err(dev, "failed to get regmap base\n");
> +		return PTR_ERR(base);
> +	}
> +
> +	map = devm_regmap_init_mmio(dev, base,
> +				    &phy_axg_mipi_pcie_analog_regmap_conf);
> +	if (IS_ERR(map)) {
> +		dev_err(dev, "failed to get HHI regmap\n");
> +		return PTR_ERR(map);
> +	}
> +	priv->regmap = map;
> +
> +	priv->phy = devm_phy_create(dev, np, &phy_axg_mipi_pcie_analog_ops);
> +	if (IS_ERR(priv->phy)) {
> +		ret = PTR_ERR(priv->phy);
> +		if (ret != -EPROBE_DEFER)
> +			dev_err(dev, "failed to create PHY\n");
> +		return ret;
> +	}
> +
> +	phy_set_drvdata(priv->phy, priv);
> +	dev_set_drvdata(dev, priv);
> +
> +	phy = devm_of_phy_provider_register(dev,
> +					    phy_axg_mipi_pcie_analog_xlate);
> +
> +	return PTR_ERR_OR_ZERO(phy);
> +}
> +
> +static const struct of_device_id phy_axg_mipi_pcie_analog_of_match[] = {
> +	{
> +		.compatible = "amlogic,axg-mipi-pcie-analog-phy",
> +	},
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, phy_axg_mipi_pcie_analog_of_match);
> +
> +static struct platform_driver phy_axg_mipi_pcie_analog_driver = {
> +	.probe = phy_axg_mipi_pcie_analog_probe,
> +	.driver = {
> +		.name = "phy-axg-mipi-pcie-analog",
> +		.of_match_table = phy_axg_mipi_pcie_analog_of_match,
> +	},
> +};
> +module_platform_driver(phy_axg_mipi_pcie_analog_driver);
> +
> +MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>");
> +MODULE_DESCRIPTION("Amlogic AXG MIPI + PCIE analog PHY driver");
> +MODULE_LICENSE("GPL v2");
> -- 
> 2.24.1
>
Neil Armstrong March 4, 2020, 9:08 a.m. UTC | #11
Hi Lorenzo,


On 03/03/2020 18:19, Lorenzo Pieralisi wrote:
> On Fri, Jan 24, 2020 at 12:29:41AM +0100, Remi Pommarel wrote:
>> This adds support for the MIPI analog PHY which is also used for PCIE
>> found in the Amlogic AXG SoC Family.
>>
>> MIPI or PCIE selection is done by the #phy-cells, making the mode
>> static and exclusive.
>>
>> For now only PCIE fonctionality is supported.
>>
>> This PHY will be used to replace the mipi_enable clock gating logic
>> which was mistakenly added in the clock subsystem. This also activate
>> a non documented band gap bit in those registers that allows reliable
>> PCIE clock signal generation on AXG platforms.
>>
>> Signed-off-by: Remi Pommarel <repk@triplefau.lt>
>> ---
>>  drivers/phy/amlogic/Kconfig                   |  11 +
>>  drivers/phy/amlogic/Makefile                  |  11 +-
>>  .../amlogic/phy-meson-axg-mipi-pcie-analog.c  | 188 ++++++++++++++++++
>>  3 files changed, 205 insertions(+), 5 deletions(-)
>>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> 
> Kishon, Neil,
> 
> can you please review/ack this patch and patch 6 ?

Sure, it was already acked by jerome, but it's also ok for me:

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>

Neil
> 
> I would like to queue the series shortly, thanks.
> 
> Lorenzo
> 
>> diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig
>> index af774ac2b934..8c9cf2403591 100644
>> --- a/drivers/phy/amlogic/Kconfig
>> +++ b/drivers/phy/amlogic/Kconfig
>> @@ -59,3 +59,14 @@ config PHY_MESON_G12A_USB3_PCIE
>>  	  Enable this to support the Meson USB3 + PCIE Combo PHY found
>>  	  in Meson G12A SoCs.
>>  	  If unsure, say N.
>> +
>> +config PHY_MESON_AXG_MIPI_PCIE_ANALOG
>> +	tristate "Meson AXG MIPI + PCIE analog PHY driver"
>> +	default ARCH_MESON
>> +	depends on OF && (ARCH_MESON || COMPILE_TEST)
>> +	select GENERIC_PHY
>> +	select REGMAP_MMIO
>> +	help
>> +	  Enable this to support the Meson MIPI + PCIE analog PHY
>> +	  found in Meson AXG SoCs.
>> +	  If unsure, say N.
>> diff --git a/drivers/phy/amlogic/Makefile b/drivers/phy/amlogic/Makefile
>> index 11d1c42ac2be..0aecf92d796a 100644
>> --- a/drivers/phy/amlogic/Makefile
>> +++ b/drivers/phy/amlogic/Makefile
>> @@ -1,6 +1,7 @@
>>  # SPDX-License-Identifier: GPL-2.0-only
>> -obj-$(CONFIG_PHY_MESON8B_USB2)		+= phy-meson8b-usb2.o
>> -obj-$(CONFIG_PHY_MESON_GXL_USB2)	+= phy-meson-gxl-usb2.o
>> -obj-$(CONFIG_PHY_MESON_G12A_USB2)	+= phy-meson-g12a-usb2.o
>> -obj-$(CONFIG_PHY_MESON_GXL_USB3)	+= phy-meson-gxl-usb3.o
>> -obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE)	+= phy-meson-g12a-usb3-pcie.o
>> +obj-$(CONFIG_PHY_MESON8B_USB2)			+= phy-meson8b-usb2.o
>> +obj-$(CONFIG_PHY_MESON_GXL_USB2)		+= phy-meson-gxl-usb2.o
>> +obj-$(CONFIG_PHY_MESON_G12A_USB2)		+= phy-meson-g12a-usb2.o
>> +obj-$(CONFIG_PHY_MESON_GXL_USB3)		+= phy-meson-gxl-usb3.o
>> +obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE)		+= phy-meson-g12a-usb3-pcie.o
>> +obj-$(CONFIG_PHY_MESON_AXG_MIPI_PCIE_ANALOG)	+= phy-meson-axg-mipi-pcie-analog.o
>> diff --git a/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
>> new file mode 100644
>> index 000000000000..1431cbf885e1
>> --- /dev/null
>> +++ b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
>> @@ -0,0 +1,188 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Amlogic AXG MIPI + PCIE analog PHY driver
>> + *
>> + * Copyright (C) 2019 Remi Pommarel <repk@triplefau.lt>
>> + */
>> +#include <linux/module.h>
>> +#include <linux/phy/phy.h>
>> +#include <linux/regmap.h>
>> +#include <linux/platform_device.h>
>> +#include <dt-bindings/phy/phy.h>
>> +
>> +#define HHI_MIPI_CNTL0 0x00
>> +#define		HHI_MIPI_CNTL0_COMMON_BLOCK	GENMASK(31, 28)
>> +#define		HHI_MIPI_CNTL0_ENABLE		BIT(29)
>> +#define		HHI_MIPI_CNTL0_BANDGAP		BIT(26)
>> +#define		HHI_MIPI_CNTL0_DECODE_TO_RTERM	GENMASK(15, 12)
>> +#define		HHI_MIPI_CNTL0_OUTPUT_EN	BIT(3)
>> +
>> +#define HHI_MIPI_CNTL1 0x01
>> +#define		HHI_MIPI_CNTL1_CH0_CML_PDR_EN	BIT(12)
>> +#define		HHI_MIPI_CNTL1_LP_ABILITY	GENMASK(5, 4)
>> +#define		HHI_MIPI_CNTL1_LP_RESISTER	BIT(3)
>> +#define		HHI_MIPI_CNTL1_INPUT_SETTING	BIT(2)
>> +#define		HHI_MIPI_CNTL1_INPUT_SEL	BIT(1)
>> +#define		HHI_MIPI_CNTL1_PRBS7_EN		BIT(0)
>> +
>> +#define HHI_MIPI_CNTL2 0x02
>> +#define		HHI_MIPI_CNTL2_CH_PU		GENMASK(31, 25)
>> +#define		HHI_MIPI_CNTL2_CH_CTL		GENMASK(24, 19)
>> +#define		HHI_MIPI_CNTL2_CH0_DIGDR_EN	BIT(18)
>> +#define		HHI_MIPI_CNTL2_CH_DIGDR_EN	BIT(17)
>> +#define		HHI_MIPI_CNTL2_LPULPS_EN	BIT(16)
>> +#define		HHI_MIPI_CNTL2_CH_EN(n)		BIT(15 - (n))
>> +#define		HHI_MIPI_CNTL2_CH0_LP_CTL	GENMASK(10, 1)
>> +
>> +struct phy_axg_mipi_pcie_analog_priv {
>> +	struct phy *phy;
>> +	unsigned int mode;
>> +	struct regmap *regmap;
>> +};
>> +
>> +static const struct regmap_config phy_axg_mipi_pcie_analog_regmap_conf = {
>> +	.reg_bits = 8,
>> +	.val_bits = 32,
>> +	.reg_stride = 4,
>> +	.max_register = HHI_MIPI_CNTL2,
>> +};
>> +
>> +static int phy_axg_mipi_pcie_analog_power_on(struct phy *phy)
>> +{
>> +	struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
>> +
>> +	/* MIPI not supported yet */
>> +	if (priv->mode != PHY_TYPE_PCIE)
>> +		return -EINVAL;
>> +
>> +	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
>> +			   HHI_MIPI_CNTL0_BANDGAP, HHI_MIPI_CNTL0_BANDGAP);
>> +
>> +	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
>> +			   HHI_MIPI_CNTL0_ENABLE, HHI_MIPI_CNTL0_ENABLE);
>> +	return 0;
>> +}
>> +
>> +static int phy_axg_mipi_pcie_analog_power_off(struct phy *phy)
>> +{
>> +	struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
>> +
>> +	/* MIPI not supported yet */
>> +	if (priv->mode != PHY_TYPE_PCIE)
>> +		return -EINVAL;
>> +
>> +	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
>> +			   HHI_MIPI_CNTL0_BANDGAP, 0);
>> +	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
>> +			   HHI_MIPI_CNTL0_ENABLE, 0);
>> +	return 0;
>> +}
>> +
>> +static int phy_axg_mipi_pcie_analog_init(struct phy *phy)
>> +{
>> +	return 0;
>> +}
>> +
>> +static int phy_axg_mipi_pcie_analog_exit(struct phy *phy)
>> +{
>> +	return 0;
>> +}
>> +
>> +static const struct phy_ops phy_axg_mipi_pcie_analog_ops = {
>> +	.init = phy_axg_mipi_pcie_analog_init,
>> +	.exit = phy_axg_mipi_pcie_analog_exit,
>> +	.power_on = phy_axg_mipi_pcie_analog_power_on,
>> +	.power_off = phy_axg_mipi_pcie_analog_power_off,
>> +	.owner = THIS_MODULE,
>> +};
>> +
>> +static struct phy *phy_axg_mipi_pcie_analog_xlate(struct device *dev,
>> +						  struct of_phandle_args *args)
>> +{
>> +	struct phy_axg_mipi_pcie_analog_priv *priv = dev_get_drvdata(dev);
>> +	unsigned int mode;
>> +
>> +	if (args->args_count != 1) {
>> +		dev_err(dev, "invalid number of arguments\n");
>> +		return ERR_PTR(-EINVAL);
>> +	}
>> +
>> +	mode = args->args[0];
>> +
>> +	/* MIPI mode is not supported yet */
>> +	if (mode != PHY_TYPE_PCIE) {
>> +		dev_err(dev, "invalid phy mode select argument\n");
>> +		return ERR_PTR(-EINVAL);
>> +	}
>> +
>> +	priv->mode = mode;
>> +	return priv->phy;
>> +}
>> +
>> +static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev)
>> +{
>> +	struct phy_provider *phy;
>> +	struct device *dev = &pdev->dev;
>> +	struct phy_axg_mipi_pcie_analog_priv *priv;
>> +	struct device_node *np = dev->of_node;
>> +	struct regmap *map;
>> +	struct resource *res;
>> +	void __iomem *base;
>> +	int ret;
>> +
>> +	priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
>> +	if (!priv)
>> +		return -ENOMEM;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	base = devm_ioremap_resource(dev, res);
>> +	if (IS_ERR(base)) {
>> +		dev_err(dev, "failed to get regmap base\n");
>> +		return PTR_ERR(base);
>> +	}
>> +
>> +	map = devm_regmap_init_mmio(dev, base,
>> +				    &phy_axg_mipi_pcie_analog_regmap_conf);
>> +	if (IS_ERR(map)) {
>> +		dev_err(dev, "failed to get HHI regmap\n");
>> +		return PTR_ERR(map);
>> +	}
>> +	priv->regmap = map;
>> +
>> +	priv->phy = devm_phy_create(dev, np, &phy_axg_mipi_pcie_analog_ops);
>> +	if (IS_ERR(priv->phy)) {
>> +		ret = PTR_ERR(priv->phy);
>> +		if (ret != -EPROBE_DEFER)
>> +			dev_err(dev, "failed to create PHY\n");
>> +		return ret;
>> +	}
>> +
>> +	phy_set_drvdata(priv->phy, priv);
>> +	dev_set_drvdata(dev, priv);
>> +
>> +	phy = devm_of_phy_provider_register(dev,
>> +					    phy_axg_mipi_pcie_analog_xlate);
>> +
>> +	return PTR_ERR_OR_ZERO(phy);
>> +}
>> +
>> +static const struct of_device_id phy_axg_mipi_pcie_analog_of_match[] = {
>> +	{
>> +		.compatible = "amlogic,axg-mipi-pcie-analog-phy",
>> +	},
>> +	{ },
>> +};
>> +MODULE_DEVICE_TABLE(of, phy_axg_mipi_pcie_analog_of_match);
>> +
>> +static struct platform_driver phy_axg_mipi_pcie_analog_driver = {
>> +	.probe = phy_axg_mipi_pcie_analog_probe,
>> +	.driver = {
>> +		.name = "phy-axg-mipi-pcie-analog",
>> +		.of_match_table = phy_axg_mipi_pcie_analog_of_match,
>> +	},
>> +};
>> +module_platform_driver(phy_axg_mipi_pcie_analog_driver);
>> +
>> +MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>");
>> +MODULE_DESCRIPTION("Amlogic AXG MIPI + PCIE analog PHY driver");
>> +MODULE_LICENSE("GPL v2");
>> -- 
>> 2.24.1
>>
Lorenzo Pieralisi March 4, 2020, 10:44 a.m. UTC | #12
On Wed, Mar 04, 2020 at 10:08:55AM +0100, Neil Armstrong wrote:
> Hi Lorenzo,
> 
> 
> On 03/03/2020 18:19, Lorenzo Pieralisi wrote:
> > On Fri, Jan 24, 2020 at 12:29:41AM +0100, Remi Pommarel wrote:
> >> This adds support for the MIPI analog PHY which is also used for PCIE
> >> found in the Amlogic AXG SoC Family.
> >>
> >> MIPI or PCIE selection is done by the #phy-cells, making the mode
> >> static and exclusive.
> >>
> >> For now only PCIE fonctionality is supported.
> >>
> >> This PHY will be used to replace the mipi_enable clock gating logic
> >> which was mistakenly added in the clock subsystem. This also activate
> >> a non documented band gap bit in those registers that allows reliable
> >> PCIE clock signal generation on AXG platforms.
> >>
> >> Signed-off-by: Remi Pommarel <repk@triplefau.lt>
> >> ---
> >>  drivers/phy/amlogic/Kconfig                   |  11 +
> >>  drivers/phy/amlogic/Makefile                  |  11 +-
> >>  .../amlogic/phy-meson-axg-mipi-pcie-analog.c  | 188 ++++++++++++++++++
> >>  3 files changed, 205 insertions(+), 5 deletions(-)
> >>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> > 
> > Kishon, Neil,
> > 
> > can you please review/ack this patch and patch 6 ?
> 
> Sure, it was already acked by jerome, but it's also ok for me:
> 
> Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>

Thanks. Sorry for the pedantry but on patch (6) too.

Lorenzo

> Neil
> > 
> > I would like to queue the series shortly, thanks.
> > 
> > Lorenzo
> > 
> >> diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig
> >> index af774ac2b934..8c9cf2403591 100644
> >> --- a/drivers/phy/amlogic/Kconfig
> >> +++ b/drivers/phy/amlogic/Kconfig
> >> @@ -59,3 +59,14 @@ config PHY_MESON_G12A_USB3_PCIE
> >>  	  Enable this to support the Meson USB3 + PCIE Combo PHY found
> >>  	  in Meson G12A SoCs.
> >>  	  If unsure, say N.
> >> +
> >> +config PHY_MESON_AXG_MIPI_PCIE_ANALOG
> >> +	tristate "Meson AXG MIPI + PCIE analog PHY driver"
> >> +	default ARCH_MESON
> >> +	depends on OF && (ARCH_MESON || COMPILE_TEST)
> >> +	select GENERIC_PHY
> >> +	select REGMAP_MMIO
> >> +	help
> >> +	  Enable this to support the Meson MIPI + PCIE analog PHY
> >> +	  found in Meson AXG SoCs.
> >> +	  If unsure, say N.
> >> diff --git a/drivers/phy/amlogic/Makefile b/drivers/phy/amlogic/Makefile
> >> index 11d1c42ac2be..0aecf92d796a 100644
> >> --- a/drivers/phy/amlogic/Makefile
> >> +++ b/drivers/phy/amlogic/Makefile
> >> @@ -1,6 +1,7 @@
> >>  # SPDX-License-Identifier: GPL-2.0-only
> >> -obj-$(CONFIG_PHY_MESON8B_USB2)		+= phy-meson8b-usb2.o
> >> -obj-$(CONFIG_PHY_MESON_GXL_USB2)	+= phy-meson-gxl-usb2.o
> >> -obj-$(CONFIG_PHY_MESON_G12A_USB2)	+= phy-meson-g12a-usb2.o
> >> -obj-$(CONFIG_PHY_MESON_GXL_USB3)	+= phy-meson-gxl-usb3.o
> >> -obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE)	+= phy-meson-g12a-usb3-pcie.o
> >> +obj-$(CONFIG_PHY_MESON8B_USB2)			+= phy-meson8b-usb2.o
> >> +obj-$(CONFIG_PHY_MESON_GXL_USB2)		+= phy-meson-gxl-usb2.o
> >> +obj-$(CONFIG_PHY_MESON_G12A_USB2)		+= phy-meson-g12a-usb2.o
> >> +obj-$(CONFIG_PHY_MESON_GXL_USB3)		+= phy-meson-gxl-usb3.o
> >> +obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE)		+= phy-meson-g12a-usb3-pcie.o
> >> +obj-$(CONFIG_PHY_MESON_AXG_MIPI_PCIE_ANALOG)	+= phy-meson-axg-mipi-pcie-analog.o
> >> diff --git a/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> >> new file mode 100644
> >> index 000000000000..1431cbf885e1
> >> --- /dev/null
> >> +++ b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> >> @@ -0,0 +1,188 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * Amlogic AXG MIPI + PCIE analog PHY driver
> >> + *
> >> + * Copyright (C) 2019 Remi Pommarel <repk@triplefau.lt>
> >> + */
> >> +#include <linux/module.h>
> >> +#include <linux/phy/phy.h>
> >> +#include <linux/regmap.h>
> >> +#include <linux/platform_device.h>
> >> +#include <dt-bindings/phy/phy.h>
> >> +
> >> +#define HHI_MIPI_CNTL0 0x00
> >> +#define		HHI_MIPI_CNTL0_COMMON_BLOCK	GENMASK(31, 28)
> >> +#define		HHI_MIPI_CNTL0_ENABLE		BIT(29)
> >> +#define		HHI_MIPI_CNTL0_BANDGAP		BIT(26)
> >> +#define		HHI_MIPI_CNTL0_DECODE_TO_RTERM	GENMASK(15, 12)
> >> +#define		HHI_MIPI_CNTL0_OUTPUT_EN	BIT(3)
> >> +
> >> +#define HHI_MIPI_CNTL1 0x01
> >> +#define		HHI_MIPI_CNTL1_CH0_CML_PDR_EN	BIT(12)
> >> +#define		HHI_MIPI_CNTL1_LP_ABILITY	GENMASK(5, 4)
> >> +#define		HHI_MIPI_CNTL1_LP_RESISTER	BIT(3)
> >> +#define		HHI_MIPI_CNTL1_INPUT_SETTING	BIT(2)
> >> +#define		HHI_MIPI_CNTL1_INPUT_SEL	BIT(1)
> >> +#define		HHI_MIPI_CNTL1_PRBS7_EN		BIT(0)
> >> +
> >> +#define HHI_MIPI_CNTL2 0x02
> >> +#define		HHI_MIPI_CNTL2_CH_PU		GENMASK(31, 25)
> >> +#define		HHI_MIPI_CNTL2_CH_CTL		GENMASK(24, 19)
> >> +#define		HHI_MIPI_CNTL2_CH0_DIGDR_EN	BIT(18)
> >> +#define		HHI_MIPI_CNTL2_CH_DIGDR_EN	BIT(17)
> >> +#define		HHI_MIPI_CNTL2_LPULPS_EN	BIT(16)
> >> +#define		HHI_MIPI_CNTL2_CH_EN(n)		BIT(15 - (n))
> >> +#define		HHI_MIPI_CNTL2_CH0_LP_CTL	GENMASK(10, 1)
> >> +
> >> +struct phy_axg_mipi_pcie_analog_priv {
> >> +	struct phy *phy;
> >> +	unsigned int mode;
> >> +	struct regmap *regmap;
> >> +};
> >> +
> >> +static const struct regmap_config phy_axg_mipi_pcie_analog_regmap_conf = {
> >> +	.reg_bits = 8,
> >> +	.val_bits = 32,
> >> +	.reg_stride = 4,
> >> +	.max_register = HHI_MIPI_CNTL2,
> >> +};
> >> +
> >> +static int phy_axg_mipi_pcie_analog_power_on(struct phy *phy)
> >> +{
> >> +	struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
> >> +
> >> +	/* MIPI not supported yet */
> >> +	if (priv->mode != PHY_TYPE_PCIE)
> >> +		return -EINVAL;
> >> +
> >> +	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> >> +			   HHI_MIPI_CNTL0_BANDGAP, HHI_MIPI_CNTL0_BANDGAP);
> >> +
> >> +	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> >> +			   HHI_MIPI_CNTL0_ENABLE, HHI_MIPI_CNTL0_ENABLE);
> >> +	return 0;
> >> +}
> >> +
> >> +static int phy_axg_mipi_pcie_analog_power_off(struct phy *phy)
> >> +{
> >> +	struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
> >> +
> >> +	/* MIPI not supported yet */
> >> +	if (priv->mode != PHY_TYPE_PCIE)
> >> +		return -EINVAL;
> >> +
> >> +	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> >> +			   HHI_MIPI_CNTL0_BANDGAP, 0);
> >> +	regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> >> +			   HHI_MIPI_CNTL0_ENABLE, 0);
> >> +	return 0;
> >> +}
> >> +
> >> +static int phy_axg_mipi_pcie_analog_init(struct phy *phy)
> >> +{
> >> +	return 0;
> >> +}
> >> +
> >> +static int phy_axg_mipi_pcie_analog_exit(struct phy *phy)
> >> +{
> >> +	return 0;
> >> +}
> >> +
> >> +static const struct phy_ops phy_axg_mipi_pcie_analog_ops = {
> >> +	.init = phy_axg_mipi_pcie_analog_init,
> >> +	.exit = phy_axg_mipi_pcie_analog_exit,
> >> +	.power_on = phy_axg_mipi_pcie_analog_power_on,
> >> +	.power_off = phy_axg_mipi_pcie_analog_power_off,
> >> +	.owner = THIS_MODULE,
> >> +};
> >> +
> >> +static struct phy *phy_axg_mipi_pcie_analog_xlate(struct device *dev,
> >> +						  struct of_phandle_args *args)
> >> +{
> >> +	struct phy_axg_mipi_pcie_analog_priv *priv = dev_get_drvdata(dev);
> >> +	unsigned int mode;
> >> +
> >> +	if (args->args_count != 1) {
> >> +		dev_err(dev, "invalid number of arguments\n");
> >> +		return ERR_PTR(-EINVAL);
> >> +	}
> >> +
> >> +	mode = args->args[0];
> >> +
> >> +	/* MIPI mode is not supported yet */
> >> +	if (mode != PHY_TYPE_PCIE) {
> >> +		dev_err(dev, "invalid phy mode select argument\n");
> >> +		return ERR_PTR(-EINVAL);
> >> +	}
> >> +
> >> +	priv->mode = mode;
> >> +	return priv->phy;
> >> +}
> >> +
> >> +static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev)
> >> +{
> >> +	struct phy_provider *phy;
> >> +	struct device *dev = &pdev->dev;
> >> +	struct phy_axg_mipi_pcie_analog_priv *priv;
> >> +	struct device_node *np = dev->of_node;
> >> +	struct regmap *map;
> >> +	struct resource *res;
> >> +	void __iomem *base;
> >> +	int ret;
> >> +
> >> +	priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
> >> +	if (!priv)
> >> +		return -ENOMEM;
> >> +
> >> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> +	base = devm_ioremap_resource(dev, res);
> >> +	if (IS_ERR(base)) {
> >> +		dev_err(dev, "failed to get regmap base\n");
> >> +		return PTR_ERR(base);
> >> +	}
> >> +
> >> +	map = devm_regmap_init_mmio(dev, base,
> >> +				    &phy_axg_mipi_pcie_analog_regmap_conf);
> >> +	if (IS_ERR(map)) {
> >> +		dev_err(dev, "failed to get HHI regmap\n");
> >> +		return PTR_ERR(map);
> >> +	}
> >> +	priv->regmap = map;
> >> +
> >> +	priv->phy = devm_phy_create(dev, np, &phy_axg_mipi_pcie_analog_ops);
> >> +	if (IS_ERR(priv->phy)) {
> >> +		ret = PTR_ERR(priv->phy);
> >> +		if (ret != -EPROBE_DEFER)
> >> +			dev_err(dev, "failed to create PHY\n");
> >> +		return ret;
> >> +	}
> >> +
> >> +	phy_set_drvdata(priv->phy, priv);
> >> +	dev_set_drvdata(dev, priv);
> >> +
> >> +	phy = devm_of_phy_provider_register(dev,
> >> +					    phy_axg_mipi_pcie_analog_xlate);
> >> +
> >> +	return PTR_ERR_OR_ZERO(phy);
> >> +}
> >> +
> >> +static const struct of_device_id phy_axg_mipi_pcie_analog_of_match[] = {
> >> +	{
> >> +		.compatible = "amlogic,axg-mipi-pcie-analog-phy",
> >> +	},
> >> +	{ },
> >> +};
> >> +MODULE_DEVICE_TABLE(of, phy_axg_mipi_pcie_analog_of_match);
> >> +
> >> +static struct platform_driver phy_axg_mipi_pcie_analog_driver = {
> >> +	.probe = phy_axg_mipi_pcie_analog_probe,
> >> +	.driver = {
> >> +		.name = "phy-axg-mipi-pcie-analog",
> >> +		.of_match_table = phy_axg_mipi_pcie_analog_of_match,
> >> +	},
> >> +};
> >> +module_platform_driver(phy_axg_mipi_pcie_analog_driver);
> >> +
> >> +MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>");
> >> +MODULE_DESCRIPTION("Amlogic AXG MIPI + PCIE analog PHY driver");
> >> +MODULE_LICENSE("GPL v2");
> >> -- 
> >> 2.24.1
> >>
>
Neil Armstrong March 4, 2020, 10:47 a.m. UTC | #13
On 24/01/2020 00:29, Remi Pommarel wrote:
> This adds support for the PCI PHY found in the Amlogic AXG SoC Family.
> This will allow to mutualize code in pci-meson.c between AXG and G12A
> SoC.
> 
> This PHY also uses and chains an analog PHY, which on AXG platform
> is needed to have reliable PCIe communication.
> 
> Signed-off-by: Remi Pommarel <repk@triplefau.lt>
> ---
>  drivers/phy/amlogic/Kconfig              |  11 ++
>  drivers/phy/amlogic/Makefile             |   1 +
>  drivers/phy/amlogic/phy-meson-axg-pcie.c | 192 +++++++++++++++++++++++
>  3 files changed, 204 insertions(+)
>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-pcie.c
> 
> diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig
> index 8c9cf2403591..71801e30d601 100644
> --- a/drivers/phy/amlogic/Kconfig
> +++ b/drivers/phy/amlogic/Kconfig
> @@ -60,6 +60,17 @@ config PHY_MESON_G12A_USB3_PCIE
>  	  in Meson G12A SoCs.
>  	  If unsure, say N.
>  
> +config PHY_MESON_AXG_PCIE
> +	tristate "Meson AXG PCIE PHY driver"
> +	default ARCH_MESON
> +	depends on OF && (ARCH_MESON || COMPILE_TEST)
> +	select GENERIC_PHY
> +	select REGMAP_MMIO
> +	help
> +	  Enable this to support the Meson MIPI + PCIE PHY found
> +	  in Meson AXG SoCs.
> +	  If unsure, say N.
> +
>  config PHY_MESON_AXG_MIPI_PCIE_ANALOG
>  	tristate "Meson AXG MIPI + PCIE analog PHY driver"
>  	default ARCH_MESON
> diff --git a/drivers/phy/amlogic/Makefile b/drivers/phy/amlogic/Makefile
> index 0aecf92d796a..e2baa133f7af 100644
> --- a/drivers/phy/amlogic/Makefile
> +++ b/drivers/phy/amlogic/Makefile
> @@ -4,4 +4,5 @@ obj-$(CONFIG_PHY_MESON_GXL_USB2)		+= phy-meson-gxl-usb2.o
>  obj-$(CONFIG_PHY_MESON_G12A_USB2)		+= phy-meson-g12a-usb2.o
>  obj-$(CONFIG_PHY_MESON_GXL_USB3)		+= phy-meson-gxl-usb3.o
>  obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE)		+= phy-meson-g12a-usb3-pcie.o
> +obj-$(CONFIG_PHY_MESON_AXG_PCIE)		+= phy-meson-axg-pcie.o
>  obj-$(CONFIG_PHY_MESON_AXG_MIPI_PCIE_ANALOG)	+= phy-meson-axg-mipi-pcie-analog.o
> diff --git a/drivers/phy/amlogic/phy-meson-axg-pcie.c b/drivers/phy/amlogic/phy-meson-axg-pcie.c
> new file mode 100644
> index 000000000000..377ed0dcd0d9
> --- /dev/null
> +++ b/drivers/phy/amlogic/phy-meson-axg-pcie.c
> @@ -0,0 +1,192 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Amlogic AXG PCIE PHY driver
> + *
> + * Copyright (C) 2020 Remi Pommarel <repk@triplefau.lt>
> + */
> +#include <linux/module.h>
> +#include <linux/phy/phy.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +#include <linux/platform_device.h>
> +#include <linux/bitfield.h>
> +#include <dt-bindings/phy/phy.h>
> +
> +#define MESON_PCIE_REG0 0x00
> +#define		MESON_PCIE_COMMON_CLK	BIT(4)
> +#define		MESON_PCIE_PORT_SEL	GENMASK(3, 2)
> +#define		MESON_PCIE_CLK		BIT(1)
> +#define		MESON_PCIE_POWERDOWN	BIT(0)
> +
> +#define MESON_PCIE_TWO_X1		FIELD_PREP(MESON_PCIE_PORT_SEL, 0x3)
> +#define MESON_PCIE_COMMON_REF_CLK	FIELD_PREP(MESON_PCIE_COMMON_CLK, 0x1)
> +#define MESON_PCIE_PHY_INIT		(MESON_PCIE_TWO_X1 |		\
> +					 MESON_PCIE_COMMON_REF_CLK)
> +#define MESON_PCIE_RESET_DELAY		500
> +
> +struct phy_axg_pcie_priv {
> +	struct phy *phy;
> +	struct phy *analog;
> +	struct regmap *regmap;
> +	struct reset_control *reset;
> +};
> +
> +static const struct regmap_config phy_axg_pcie_regmap_conf = {
> +	.reg_bits = 8,
> +	.val_bits = 32,
> +	.reg_stride = 4,
> +	.max_register = MESON_PCIE_REG0,
> +};
> +
> +static int phy_axg_pcie_power_on(struct phy *phy)
> +{
> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
> +	int ret;
> +
> +	ret = phy_power_on(priv->analog);
> +	if (ret != 0)
> +		return ret;
> +
> +	regmap_update_bits(priv->regmap, MESON_PCIE_REG0,
> +			   MESON_PCIE_POWERDOWN, 0);
> +	return 0;
> +}
> +
> +static int phy_axg_pcie_power_off(struct phy *phy)
> +{
> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
> +	int ret;
> +
> +	ret = phy_power_off(priv->analog);
> +	if (ret != 0)
> +		return ret;
> +
> +	regmap_update_bits(priv->regmap, MESON_PCIE_REG0,
> +			   MESON_PCIE_POWERDOWN, 1);
> +	return 0;
> +}
> +
> +static int phy_axg_pcie_init(struct phy *phy)
> +{
> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
> +	int ret;
> +
> +	ret = phy_init(priv->analog);
> +	if (ret != 0)
> +		return ret;
> +
> +	regmap_write(priv->regmap, MESON_PCIE_REG0, MESON_PCIE_PHY_INIT);
> +	return reset_control_reset(priv->reset);
> +}
> +
> +static int phy_axg_pcie_exit(struct phy *phy)
> +{
> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
> +	int ret;
> +
> +	ret = phy_exit(priv->analog);
> +	if (ret != 0)
> +		return ret;
> +
> +	return reset_control_reset(priv->reset);
> +}
> +
> +static int phy_axg_pcie_reset(struct phy *phy)
> +{
> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
> +	int ret = 0;
> +
> +	ret = phy_reset(priv->analog);
> +	if (ret != 0)
> +		goto out;
> +
> +	ret = reset_control_assert(priv->reset);
> +	if (ret != 0)
> +		goto out;
> +	udelay(MESON_PCIE_RESET_DELAY);
> +
> +	ret = reset_control_deassert(priv->reset);
> +	if (ret != 0)
> +		goto out;
> +	udelay(MESON_PCIE_RESET_DELAY);
> +
> +out:
> +	return ret;
> +}
> +
> +static const struct phy_ops phy_axg_pcie_ops = {
> +	.init = phy_axg_pcie_init,
> +	.exit = phy_axg_pcie_exit,
> +	.power_on = phy_axg_pcie_power_on,
> +	.power_off = phy_axg_pcie_power_off,
> +	.reset = phy_axg_pcie_reset,
> +	.owner = THIS_MODULE,
> +};
> +
> +static int phy_axg_pcie_probe(struct platform_device *pdev)
> +{
> +	struct phy_provider *pphy;
> +	struct device *dev = &pdev->dev;
> +	struct phy_axg_pcie_priv *priv;
> +	struct device_node *np = dev->of_node;
> +	struct resource *res;
> +	void __iomem *base;
> +	int ret;
> +
> +	priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->phy = devm_phy_create(dev, np, &phy_axg_pcie_ops);
> +	if (IS_ERR(priv->phy)) {
> +		ret = PTR_ERR(priv->phy);
> +		if (ret != -EPROBE_DEFER)
> +			dev_err(dev, "failed to create PHY\n");
> +		return ret;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(base))
> +		return PTR_ERR(base);
> +
> +	priv->regmap = devm_regmap_init_mmio(dev, base,
> +					     &phy_axg_pcie_regmap_conf);
> +	if (IS_ERR(priv->regmap))
> +		return PTR_ERR(priv->regmap);
> +
> +	priv->reset = devm_reset_control_array_get(dev, false, false);
> +	if (IS_ERR(priv->reset))
> +		return PTR_ERR(priv->reset);
> +
> +	priv->analog = devm_phy_get(dev, "analog");
> +	if (IS_ERR(priv->analog))
> +		return PTR_ERR(priv->analog);
> +
> +	phy_set_drvdata(priv->phy, priv);
> +	dev_set_drvdata(dev, priv);
> +	pphy = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> +
> +	return PTR_ERR_OR_ZERO(pphy);
> +}
> +
> +static const struct of_device_id phy_axg_pcie_of_match[] = {
> +	{
> +		.compatible = "amlogic,axg-pcie-phy",
> +	},
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, phy_axg_pcie_of_match);
> +
> +static struct platform_driver phy_axg_pcie_driver = {
> +	.probe = phy_axg_pcie_probe,
> +	.driver = {
> +		.name = "phy-axg-pcie",
> +		.of_match_table = phy_axg_pcie_of_match,
> +	},
> +};
> +module_platform_driver(phy_axg_pcie_driver);
> +
> +MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>");
> +MODULE_DESCRIPTION("Amlogic AXG PCIE PHY driver");
> +MODULE_LICENSE("GPL v2");
> 

The changes since v5 are done (make analog phy mandatory), ok for me then.

Reviewed-by: Neil Armstrong <narmstrong@baylibre.com>
Kishon Vijay Abraham I March 4, 2020, 11:01 a.m. UTC | #14
On 24/01/20 4:59 am, Remi Pommarel wrote:
> This adds support for the PCI PHY found in the Amlogic AXG SoC Family.
> This will allow to mutualize code in pci-meson.c between AXG and G12A
> SoC.
> 
> This PHY also uses and chains an analog PHY, which on AXG platform
> is needed to have reliable PCIe communication.

Is the analog PHY an independent block and can be used with other PHYs?

For the patch itself
Acked-by: Kishon Vijay Abraham I <kishon@ti.com>

Thanks
Kishon
> 
> Signed-off-by: Remi Pommarel <repk@triplefau.lt>
> ---
>  drivers/phy/amlogic/Kconfig              |  11 ++
>  drivers/phy/amlogic/Makefile             |   1 +
>  drivers/phy/amlogic/phy-meson-axg-pcie.c | 192 +++++++++++++++++++++++
>  3 files changed, 204 insertions(+)
>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-pcie.c
> 
> diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig
> index 8c9cf2403591..71801e30d601 100644
> --- a/drivers/phy/amlogic/Kconfig
> +++ b/drivers/phy/amlogic/Kconfig
> @@ -60,6 +60,17 @@ config PHY_MESON_G12A_USB3_PCIE
>  	  in Meson G12A SoCs.
>  	  If unsure, say N.
>  
> +config PHY_MESON_AXG_PCIE
> +	tristate "Meson AXG PCIE PHY driver"
> +	default ARCH_MESON
> +	depends on OF && (ARCH_MESON || COMPILE_TEST)
> +	select GENERIC_PHY
> +	select REGMAP_MMIO
> +	help
> +	  Enable this to support the Meson MIPI + PCIE PHY found
> +	  in Meson AXG SoCs.
> +	  If unsure, say N.
> +
>  config PHY_MESON_AXG_MIPI_PCIE_ANALOG
>  	tristate "Meson AXG MIPI + PCIE analog PHY driver"
>  	default ARCH_MESON
> diff --git a/drivers/phy/amlogic/Makefile b/drivers/phy/amlogic/Makefile
> index 0aecf92d796a..e2baa133f7af 100644
> --- a/drivers/phy/amlogic/Makefile
> +++ b/drivers/phy/amlogic/Makefile
> @@ -4,4 +4,5 @@ obj-$(CONFIG_PHY_MESON_GXL_USB2)		+= phy-meson-gxl-usb2.o
>  obj-$(CONFIG_PHY_MESON_G12A_USB2)		+= phy-meson-g12a-usb2.o
>  obj-$(CONFIG_PHY_MESON_GXL_USB3)		+= phy-meson-gxl-usb3.o
>  obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE)		+= phy-meson-g12a-usb3-pcie.o
> +obj-$(CONFIG_PHY_MESON_AXG_PCIE)		+= phy-meson-axg-pcie.o
>  obj-$(CONFIG_PHY_MESON_AXG_MIPI_PCIE_ANALOG)	+= phy-meson-axg-mipi-pcie-analog.o
> diff --git a/drivers/phy/amlogic/phy-meson-axg-pcie.c b/drivers/phy/amlogic/phy-meson-axg-pcie.c
> new file mode 100644
> index 000000000000..377ed0dcd0d9
> --- /dev/null
> +++ b/drivers/phy/amlogic/phy-meson-axg-pcie.c
> @@ -0,0 +1,192 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Amlogic AXG PCIE PHY driver
> + *
> + * Copyright (C) 2020 Remi Pommarel <repk@triplefau.lt>
> + */
> +#include <linux/module.h>
> +#include <linux/phy/phy.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +#include <linux/platform_device.h>
> +#include <linux/bitfield.h>
> +#include <dt-bindings/phy/phy.h>
> +
> +#define MESON_PCIE_REG0 0x00
> +#define		MESON_PCIE_COMMON_CLK	BIT(4)
> +#define		MESON_PCIE_PORT_SEL	GENMASK(3, 2)
> +#define		MESON_PCIE_CLK		BIT(1)
> +#define		MESON_PCIE_POWERDOWN	BIT(0)
> +
> +#define MESON_PCIE_TWO_X1		FIELD_PREP(MESON_PCIE_PORT_SEL, 0x3)
> +#define MESON_PCIE_COMMON_REF_CLK	FIELD_PREP(MESON_PCIE_COMMON_CLK, 0x1)
> +#define MESON_PCIE_PHY_INIT		(MESON_PCIE_TWO_X1 |		\
> +					 MESON_PCIE_COMMON_REF_CLK)
> +#define MESON_PCIE_RESET_DELAY		500
> +
> +struct phy_axg_pcie_priv {
> +	struct phy *phy;
> +	struct phy *analog;
> +	struct regmap *regmap;
> +	struct reset_control *reset;
> +};
> +
> +static const struct regmap_config phy_axg_pcie_regmap_conf = {
> +	.reg_bits = 8,
> +	.val_bits = 32,
> +	.reg_stride = 4,
> +	.max_register = MESON_PCIE_REG0,
> +};
> +
> +static int phy_axg_pcie_power_on(struct phy *phy)
> +{
> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
> +	int ret;
> +
> +	ret = phy_power_on(priv->analog);
> +	if (ret != 0)
> +		return ret;
> +
> +	regmap_update_bits(priv->regmap, MESON_PCIE_REG0,
> +			   MESON_PCIE_POWERDOWN, 0);
> +	return 0;
> +}
> +
> +static int phy_axg_pcie_power_off(struct phy *phy)
> +{
> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
> +	int ret;
> +
> +	ret = phy_power_off(priv->analog);
> +	if (ret != 0)
> +		return ret;
> +
> +	regmap_update_bits(priv->regmap, MESON_PCIE_REG0,
> +			   MESON_PCIE_POWERDOWN, 1);
> +	return 0;
> +}
> +
> +static int phy_axg_pcie_init(struct phy *phy)
> +{
> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
> +	int ret;
> +
> +	ret = phy_init(priv->analog);
> +	if (ret != 0)
> +		return ret;
> +
> +	regmap_write(priv->regmap, MESON_PCIE_REG0, MESON_PCIE_PHY_INIT);
> +	return reset_control_reset(priv->reset);
> +}
> +
> +static int phy_axg_pcie_exit(struct phy *phy)
> +{
> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
> +	int ret;
> +
> +	ret = phy_exit(priv->analog);
> +	if (ret != 0)
> +		return ret;
> +
> +	return reset_control_reset(priv->reset);
> +}
> +
> +static int phy_axg_pcie_reset(struct phy *phy)
> +{
> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
> +	int ret = 0;
> +
> +	ret = phy_reset(priv->analog);
> +	if (ret != 0)
> +		goto out;
> +
> +	ret = reset_control_assert(priv->reset);
> +	if (ret != 0)
> +		goto out;
> +	udelay(MESON_PCIE_RESET_DELAY);
> +
> +	ret = reset_control_deassert(priv->reset);
> +	if (ret != 0)
> +		goto out;
> +	udelay(MESON_PCIE_RESET_DELAY);
> +
> +out:
> +	return ret;
> +}
> +
> +static const struct phy_ops phy_axg_pcie_ops = {
> +	.init = phy_axg_pcie_init,
> +	.exit = phy_axg_pcie_exit,
> +	.power_on = phy_axg_pcie_power_on,
> +	.power_off = phy_axg_pcie_power_off,
> +	.reset = phy_axg_pcie_reset,
> +	.owner = THIS_MODULE,
> +};
> +
> +static int phy_axg_pcie_probe(struct platform_device *pdev)
> +{
> +	struct phy_provider *pphy;
> +	struct device *dev = &pdev->dev;
> +	struct phy_axg_pcie_priv *priv;
> +	struct device_node *np = dev->of_node;
> +	struct resource *res;
> +	void __iomem *base;
> +	int ret;
> +
> +	priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->phy = devm_phy_create(dev, np, &phy_axg_pcie_ops);
> +	if (IS_ERR(priv->phy)) {
> +		ret = PTR_ERR(priv->phy);
> +		if (ret != -EPROBE_DEFER)
> +			dev_err(dev, "failed to create PHY\n");
> +		return ret;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(base))
> +		return PTR_ERR(base);
> +
> +	priv->regmap = devm_regmap_init_mmio(dev, base,
> +					     &phy_axg_pcie_regmap_conf);
> +	if (IS_ERR(priv->regmap))
> +		return PTR_ERR(priv->regmap);
> +
> +	priv->reset = devm_reset_control_array_get(dev, false, false);
> +	if (IS_ERR(priv->reset))
> +		return PTR_ERR(priv->reset);
> +
> +	priv->analog = devm_phy_get(dev, "analog");
> +	if (IS_ERR(priv->analog))
> +		return PTR_ERR(priv->analog);
> +
> +	phy_set_drvdata(priv->phy, priv);
> +	dev_set_drvdata(dev, priv);
> +	pphy = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> +
> +	return PTR_ERR_OR_ZERO(pphy);
> +}
> +
> +static const struct of_device_id phy_axg_pcie_of_match[] = {
> +	{
> +		.compatible = "amlogic,axg-pcie-phy",
> +	},
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, phy_axg_pcie_of_match);
> +
> +static struct platform_driver phy_axg_pcie_driver = {
> +	.probe = phy_axg_pcie_probe,
> +	.driver = {
> +		.name = "phy-axg-pcie",
> +		.of_match_table = phy_axg_pcie_of_match,
> +	},
> +};
> +module_platform_driver(phy_axg_pcie_driver);
> +
> +MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>");
> +MODULE_DESCRIPTION("Amlogic AXG PCIE PHY driver");
> +MODULE_LICENSE("GPL v2");
>
Lorenzo Pieralisi March 4, 2020, 12:28 p.m. UTC | #15
On Sat, Feb 29, 2020 at 05:07:43PM +0100, Kevin Hilman wrote:
> Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> writes:
> 
> > On Fri, Jan 24, 2020 at 12:29:36AM +0100, Remi Pommarel wrote:
> >> PCIe device probing failures have been seen on AXG platforms and were
> >> due to unreliable clock signal output. Setting HHI_MIPI_CNTL0[26] bit
> >> in MIPI's PHY registers solved the problem. This bit controls band gap
> >> reference.
> >> 
> >> As discussed here [1] one of these shared MIPI/PCIE analog PHY register
> >> bits was implemented in the clock driver as CLKID_MIPI_ENABLE. This adds
> >> a PHY driver to control this bit instead, as well as setting the band
> >> gap one in order to get reliable PCIE communication.
> >> 
> >> While at it add another PHY driver to control PCIE only PHY registers,
> >> making AXG code more similar to G12A platform thus allowing to remove
> >> some specific platform handling in pci-meson driver.
> >> 
> >> Please note that CLKID_MIPI_ENABLE removable will be done in a different
> >> serie.
> >> 
> >> Changes since v5:
> >>  - Add additionalProperties in device tree binding documentation
> >>  - Make analog PHY required
> >> 
> >> Changes since v4:
> >>  - Rename the shared MIPI/PCIe PHY to analog
> >>  - Chain the MIPI/PCIe PHY to the PCIe one
> >> 
> >> Changes since v3:
> >>  - Go back to the shared MIPI/PCIe phy driver solution from v2
> >>  - Remove syscon usage
> >>  - Add all dt-bindings documentation
> >> 
> >> Changes since v2:
> >>  - Remove shared MIPI/PCIE device driver and use syscon to access register
> >>    in PCIE only driver instead
> >>  - Include devicetree documentation
> >> 
> >> Changes sinve v1:
> >>  - Move HHI_MIPI_CNTL0 bit control in its own PHY driver
> >>  - Add a PHY driver for PCIE_PHY registers
> >>  - Modify pci-meson.c to make use of both PHYs and remove specific
> >>    handling for AXG and G12A
> >> 
> >> [1] https://lkml.org/lkml/2019/12/16/119
> >> 
> >> Remi Pommarel (7):
> >>   dt-bindings: Add AXG PCIE PHY bindings
> >>   dt-bindings: Add AXG shared MIPI/PCIE analog PHY bindings
> >>   dt-bindings: PCI: meson: Update PCIE bindings documentation
> >>   arm64: dts: meson-axg: Add PCIE PHY nodes
> >>   phy: amlogic: Add Amlogic AXG MIPI/PCIE analog PHY Driver
> >>   phy: amlogic: Add Amlogic AXG PCIE PHY Driver
> >>   PCI: amlogic: Use AXG PCIE
> >> 
> >>  .../bindings/pci/amlogic,meson-pcie.txt       |  22 +-
> >>  .../amlogic,meson-axg-mipi-pcie-analog.yaml   |  35 ++++
> >>  .../bindings/phy/amlogic,meson-axg-pcie.yaml  |  52 +++++
> >>  arch/arm64/boot/dts/amlogic/meson-axg.dtsi    |  16 ++
> >>  drivers/pci/controller/dwc/pci-meson.c        | 116 ++---------
> >>  drivers/phy/amlogic/Kconfig                   |  22 ++
> >>  drivers/phy/amlogic/Makefile                  |  12 +-
> >>  .../amlogic/phy-meson-axg-mipi-pcie-analog.c  | 188 +++++++++++++++++
> >>  drivers/phy/amlogic/phy-meson-axg-pcie.c      | 192 ++++++++++++++++++
> >>  9 files changed, 543 insertions(+), 112 deletions(-)
> >>  create mode 100644 Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
> >>  create mode 100644 Documentation/devicetree/bindings/phy/amlogic,meson-axg-pcie.yaml
> >>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> >>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-pcie.c
> >
> > Hi Remi,
> >
> > I am ready to pull this series in, do you want me to ? Or you prefer
> > it to go via a different tree upstream ?
> 
> To avoid conflicts, I'll take the DT patch (PATCH 4/7) through my
> amlogic tree, but feel free to take the rest.

Applied patches [1,2,3,5,6,7] to pci/amlogic for v5.7, thanks.

Lorenzo
Remi Pommarel March 4, 2020, 1:08 p.m. UTC | #16
On Wed, Mar 04, 2020 at 04:31:24PM +0530, Kishon Vijay Abraham I wrote:
> 
> 
> On 24/01/20 4:59 am, Remi Pommarel wrote:
> > This adds support for the PCI PHY found in the Amlogic AXG SoC Family.
> > This will allow to mutualize code in pci-meson.c between AXG and G12A
> > SoC.
> > 
> > This PHY also uses and chains an analog PHY, which on AXG platform
> > is needed to have reliable PCIe communication.
> 
> Is the analog PHY an independent block and can be used with other PHYs?

It is documented as a separate block yes, but I think it is unlikely
that it will be used with other PHYs than the PCIe or the MIPI one of
the AXG SoC.

Thanks,
Remi

> 
> For the patch itself
> Acked-by: Kishon Vijay Abraham I <kishon@ti.com>
> 
> Thanks
> Kishon
> > 
> > Signed-off-by: Remi Pommarel <repk@triplefau.lt>
> > ---
> >  drivers/phy/amlogic/Kconfig              |  11 ++
> >  drivers/phy/amlogic/Makefile             |   1 +
> >  drivers/phy/amlogic/phy-meson-axg-pcie.c | 192 +++++++++++++++++++++++
> >  3 files changed, 204 insertions(+)
> >  create mode 100644 drivers/phy/amlogic/phy-meson-axg-pcie.c
> > 
> > diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig
> > index 8c9cf2403591..71801e30d601 100644
> > --- a/drivers/phy/amlogic/Kconfig
> > +++ b/drivers/phy/amlogic/Kconfig
> > @@ -60,6 +60,17 @@ config PHY_MESON_G12A_USB3_PCIE
> >  	  in Meson G12A SoCs.
> >  	  If unsure, say N.
> >  
> > +config PHY_MESON_AXG_PCIE
> > +	tristate "Meson AXG PCIE PHY driver"
> > +	default ARCH_MESON
> > +	depends on OF && (ARCH_MESON || COMPILE_TEST)
> > +	select GENERIC_PHY
> > +	select REGMAP_MMIO
> > +	help
> > +	  Enable this to support the Meson MIPI + PCIE PHY found
> > +	  in Meson AXG SoCs.
> > +	  If unsure, say N.
> > +
> >  config PHY_MESON_AXG_MIPI_PCIE_ANALOG
> >  	tristate "Meson AXG MIPI + PCIE analog PHY driver"
> >  	default ARCH_MESON
> > diff --git a/drivers/phy/amlogic/Makefile b/drivers/phy/amlogic/Makefile
> > index 0aecf92d796a..e2baa133f7af 100644
> > --- a/drivers/phy/amlogic/Makefile
> > +++ b/drivers/phy/amlogic/Makefile
> > @@ -4,4 +4,5 @@ obj-$(CONFIG_PHY_MESON_GXL_USB2)		+= phy-meson-gxl-usb2.o
> >  obj-$(CONFIG_PHY_MESON_G12A_USB2)		+= phy-meson-g12a-usb2.o
> >  obj-$(CONFIG_PHY_MESON_GXL_USB3)		+= phy-meson-gxl-usb3.o
> >  obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE)		+= phy-meson-g12a-usb3-pcie.o
> > +obj-$(CONFIG_PHY_MESON_AXG_PCIE)		+= phy-meson-axg-pcie.o
> >  obj-$(CONFIG_PHY_MESON_AXG_MIPI_PCIE_ANALOG)	+= phy-meson-axg-mipi-pcie-analog.o
> > diff --git a/drivers/phy/amlogic/phy-meson-axg-pcie.c b/drivers/phy/amlogic/phy-meson-axg-pcie.c
> > new file mode 100644
> > index 000000000000..377ed0dcd0d9
> > --- /dev/null
> > +++ b/drivers/phy/amlogic/phy-meson-axg-pcie.c
> > @@ -0,0 +1,192 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Amlogic AXG PCIE PHY driver
> > + *
> > + * Copyright (C) 2020 Remi Pommarel <repk@triplefau.lt>
> > + */
> > +#include <linux/module.h>
> > +#include <linux/phy/phy.h>
> > +#include <linux/regmap.h>
> > +#include <linux/reset.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/bitfield.h>
> > +#include <dt-bindings/phy/phy.h>
> > +
> > +#define MESON_PCIE_REG0 0x00
> > +#define		MESON_PCIE_COMMON_CLK	BIT(4)
> > +#define		MESON_PCIE_PORT_SEL	GENMASK(3, 2)
> > +#define		MESON_PCIE_CLK		BIT(1)
> > +#define		MESON_PCIE_POWERDOWN	BIT(0)
> > +
> > +#define MESON_PCIE_TWO_X1		FIELD_PREP(MESON_PCIE_PORT_SEL, 0x3)
> > +#define MESON_PCIE_COMMON_REF_CLK	FIELD_PREP(MESON_PCIE_COMMON_CLK, 0x1)
> > +#define MESON_PCIE_PHY_INIT		(MESON_PCIE_TWO_X1 |		\
> > +					 MESON_PCIE_COMMON_REF_CLK)
> > +#define MESON_PCIE_RESET_DELAY		500
> > +
> > +struct phy_axg_pcie_priv {
> > +	struct phy *phy;
> > +	struct phy *analog;
> > +	struct regmap *regmap;
> > +	struct reset_control *reset;
> > +};
> > +
> > +static const struct regmap_config phy_axg_pcie_regmap_conf = {
> > +	.reg_bits = 8,
> > +	.val_bits = 32,
> > +	.reg_stride = 4,
> > +	.max_register = MESON_PCIE_REG0,
> > +};
> > +
> > +static int phy_axg_pcie_power_on(struct phy *phy)
> > +{
> > +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
> > +	int ret;
> > +
> > +	ret = phy_power_on(priv->analog);
> > +	if (ret != 0)
> > +		return ret;
> > +
> > +	regmap_update_bits(priv->regmap, MESON_PCIE_REG0,
> > +			   MESON_PCIE_POWERDOWN, 0);
> > +	return 0;
> > +}
> > +
> > +static int phy_axg_pcie_power_off(struct phy *phy)
> > +{
> > +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
> > +	int ret;
> > +
> > +	ret = phy_power_off(priv->analog);
> > +	if (ret != 0)
> > +		return ret;
> > +
> > +	regmap_update_bits(priv->regmap, MESON_PCIE_REG0,
> > +			   MESON_PCIE_POWERDOWN, 1);
> > +	return 0;
> > +}
> > +
> > +static int phy_axg_pcie_init(struct phy *phy)
> > +{
> > +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
> > +	int ret;
> > +
> > +	ret = phy_init(priv->analog);
> > +	if (ret != 0)
> > +		return ret;
> > +
> > +	regmap_write(priv->regmap, MESON_PCIE_REG0, MESON_PCIE_PHY_INIT);
> > +	return reset_control_reset(priv->reset);
> > +}
> > +
> > +static int phy_axg_pcie_exit(struct phy *phy)
> > +{
> > +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
> > +	int ret;
> > +
> > +	ret = phy_exit(priv->analog);
> > +	if (ret != 0)
> > +		return ret;
> > +
> > +	return reset_control_reset(priv->reset);
> > +}
> > +
> > +static int phy_axg_pcie_reset(struct phy *phy)
> > +{
> > +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
> > +	int ret = 0;
> > +
> > +	ret = phy_reset(priv->analog);
> > +	if (ret != 0)
> > +		goto out;
> > +
> > +	ret = reset_control_assert(priv->reset);
> > +	if (ret != 0)
> > +		goto out;
> > +	udelay(MESON_PCIE_RESET_DELAY);
> > +
> > +	ret = reset_control_deassert(priv->reset);
> > +	if (ret != 0)
> > +		goto out;
> > +	udelay(MESON_PCIE_RESET_DELAY);
> > +
> > +out:
> > +	return ret;
> > +}
> > +
> > +static const struct phy_ops phy_axg_pcie_ops = {
> > +	.init = phy_axg_pcie_init,
> > +	.exit = phy_axg_pcie_exit,
> > +	.power_on = phy_axg_pcie_power_on,
> > +	.power_off = phy_axg_pcie_power_off,
> > +	.reset = phy_axg_pcie_reset,
> > +	.owner = THIS_MODULE,
> > +};
> > +
> > +static int phy_axg_pcie_probe(struct platform_device *pdev)
> > +{
> > +	struct phy_provider *pphy;
> > +	struct device *dev = &pdev->dev;
> > +	struct phy_axg_pcie_priv *priv;
> > +	struct device_node *np = dev->of_node;
> > +	struct resource *res;
> > +	void __iomem *base;
> > +	int ret;
> > +
> > +	priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
> > +	if (!priv)
> > +		return -ENOMEM;
> > +
> > +	priv->phy = devm_phy_create(dev, np, &phy_axg_pcie_ops);
> > +	if (IS_ERR(priv->phy)) {
> > +		ret = PTR_ERR(priv->phy);
> > +		if (ret != -EPROBE_DEFER)
> > +			dev_err(dev, "failed to create PHY\n");
> > +		return ret;
> > +	}
> > +
> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	base = devm_ioremap_resource(dev, res);
> > +	if (IS_ERR(base))
> > +		return PTR_ERR(base);
> > +
> > +	priv->regmap = devm_regmap_init_mmio(dev, base,
> > +					     &phy_axg_pcie_regmap_conf);
> > +	if (IS_ERR(priv->regmap))
> > +		return PTR_ERR(priv->regmap);
> > +
> > +	priv->reset = devm_reset_control_array_get(dev, false, false);
> > +	if (IS_ERR(priv->reset))
> > +		return PTR_ERR(priv->reset);
> > +
> > +	priv->analog = devm_phy_get(dev, "analog");
> > +	if (IS_ERR(priv->analog))
> > +		return PTR_ERR(priv->analog);
> > +
> > +	phy_set_drvdata(priv->phy, priv);
> > +	dev_set_drvdata(dev, priv);
> > +	pphy = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> > +
> > +	return PTR_ERR_OR_ZERO(pphy);
> > +}
> > +
> > +static const struct of_device_id phy_axg_pcie_of_match[] = {
> > +	{
> > +		.compatible = "amlogic,axg-pcie-phy",
> > +	},
> > +	{ },
> > +};
> > +MODULE_DEVICE_TABLE(of, phy_axg_pcie_of_match);
> > +
> > +static struct platform_driver phy_axg_pcie_driver = {
> > +	.probe = phy_axg_pcie_probe,
> > +	.driver = {
> > +		.name = "phy-axg-pcie",
> > +		.of_match_table = phy_axg_pcie_of_match,
> > +	},
> > +};
> > +module_platform_driver(phy_axg_pcie_driver);
> > +
> > +MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>");
> > +MODULE_DESCRIPTION("Amlogic AXG PCIE PHY driver");
> > +MODULE_LICENSE("GPL v2");
> >
Kishon Vijay Abraham I March 5, 2020, 4:56 a.m. UTC | #17
Hi,

On 04/03/20 6:38 pm, Remi Pommarel wrote:
> On Wed, Mar 04, 2020 at 04:31:24PM +0530, Kishon Vijay Abraham I wrote:
>>
>>
>> On 24/01/20 4:59 am, Remi Pommarel wrote:
>>> This adds support for the PCI PHY found in the Amlogic AXG SoC Family.
>>> This will allow to mutualize code in pci-meson.c between AXG and G12A
>>> SoC.
>>>
>>> This PHY also uses and chains an analog PHY, which on AXG platform
>>> is needed to have reliable PCIe communication.
>>
>> Is the analog PHY an independent block and can be used with other PHYs?
> 
> It is documented as a separate block yes, but I think it is unlikely
> that it will be used with other PHYs than the PCIe or the MIPI one of
> the AXG SoC.

Shouldn't we then have a single PHY driver instead of chaining PHYs?

Thanks
Kishon

> 
> Thanks,
> Remi
> 
>>
>> For the patch itself
>> Acked-by: Kishon Vijay Abraham I <kishon@ti.com>
>>
>> Thanks
>> Kishon
>>>
>>> Signed-off-by: Remi Pommarel <repk@triplefau.lt>
>>> ---
>>>  drivers/phy/amlogic/Kconfig              |  11 ++
>>>  drivers/phy/amlogic/Makefile             |   1 +
>>>  drivers/phy/amlogic/phy-meson-axg-pcie.c | 192 +++++++++++++++++++++++
>>>  3 files changed, 204 insertions(+)
>>>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-pcie.c
>>>
>>> diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig
>>> index 8c9cf2403591..71801e30d601 100644
>>> --- a/drivers/phy/amlogic/Kconfig
>>> +++ b/drivers/phy/amlogic/Kconfig
>>> @@ -60,6 +60,17 @@ config PHY_MESON_G12A_USB3_PCIE
>>>  	  in Meson G12A SoCs.
>>>  	  If unsure, say N.
>>>  
>>> +config PHY_MESON_AXG_PCIE
>>> +	tristate "Meson AXG PCIE PHY driver"
>>> +	default ARCH_MESON
>>> +	depends on OF && (ARCH_MESON || COMPILE_TEST)
>>> +	select GENERIC_PHY
>>> +	select REGMAP_MMIO
>>> +	help
>>> +	  Enable this to support the Meson MIPI + PCIE PHY found
>>> +	  in Meson AXG SoCs.
>>> +	  If unsure, say N.
>>> +
>>>  config PHY_MESON_AXG_MIPI_PCIE_ANALOG
>>>  	tristate "Meson AXG MIPI + PCIE analog PHY driver"
>>>  	default ARCH_MESON
>>> diff --git a/drivers/phy/amlogic/Makefile b/drivers/phy/amlogic/Makefile
>>> index 0aecf92d796a..e2baa133f7af 100644
>>> --- a/drivers/phy/amlogic/Makefile
>>> +++ b/drivers/phy/amlogic/Makefile
>>> @@ -4,4 +4,5 @@ obj-$(CONFIG_PHY_MESON_GXL_USB2)		+= phy-meson-gxl-usb2.o
>>>  obj-$(CONFIG_PHY_MESON_G12A_USB2)		+= phy-meson-g12a-usb2.o
>>>  obj-$(CONFIG_PHY_MESON_GXL_USB3)		+= phy-meson-gxl-usb3.o
>>>  obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE)		+= phy-meson-g12a-usb3-pcie.o
>>> +obj-$(CONFIG_PHY_MESON_AXG_PCIE)		+= phy-meson-axg-pcie.o
>>>  obj-$(CONFIG_PHY_MESON_AXG_MIPI_PCIE_ANALOG)	+= phy-meson-axg-mipi-pcie-analog.o
>>> diff --git a/drivers/phy/amlogic/phy-meson-axg-pcie.c b/drivers/phy/amlogic/phy-meson-axg-pcie.c
>>> new file mode 100644
>>> index 000000000000..377ed0dcd0d9
>>> --- /dev/null
>>> +++ b/drivers/phy/amlogic/phy-meson-axg-pcie.c
>>> @@ -0,0 +1,192 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/*
>>> + * Amlogic AXG PCIE PHY driver
>>> + *
>>> + * Copyright (C) 2020 Remi Pommarel <repk@triplefau.lt>
>>> + */
>>> +#include <linux/module.h>
>>> +#include <linux/phy/phy.h>
>>> +#include <linux/regmap.h>
>>> +#include <linux/reset.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/bitfield.h>
>>> +#include <dt-bindings/phy/phy.h>
>>> +
>>> +#define MESON_PCIE_REG0 0x00
>>> +#define		MESON_PCIE_COMMON_CLK	BIT(4)
>>> +#define		MESON_PCIE_PORT_SEL	GENMASK(3, 2)
>>> +#define		MESON_PCIE_CLK		BIT(1)
>>> +#define		MESON_PCIE_POWERDOWN	BIT(0)
>>> +
>>> +#define MESON_PCIE_TWO_X1		FIELD_PREP(MESON_PCIE_PORT_SEL, 0x3)
>>> +#define MESON_PCIE_COMMON_REF_CLK	FIELD_PREP(MESON_PCIE_COMMON_CLK, 0x1)
>>> +#define MESON_PCIE_PHY_INIT		(MESON_PCIE_TWO_X1 |		\
>>> +					 MESON_PCIE_COMMON_REF_CLK)
>>> +#define MESON_PCIE_RESET_DELAY		500
>>> +
>>> +struct phy_axg_pcie_priv {
>>> +	struct phy *phy;
>>> +	struct phy *analog;
>>> +	struct regmap *regmap;
>>> +	struct reset_control *reset;
>>> +};
>>> +
>>> +static const struct regmap_config phy_axg_pcie_regmap_conf = {
>>> +	.reg_bits = 8,
>>> +	.val_bits = 32,
>>> +	.reg_stride = 4,
>>> +	.max_register = MESON_PCIE_REG0,
>>> +};
>>> +
>>> +static int phy_axg_pcie_power_on(struct phy *phy)
>>> +{
>>> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
>>> +	int ret;
>>> +
>>> +	ret = phy_power_on(priv->analog);
>>> +	if (ret != 0)
>>> +		return ret;
>>> +
>>> +	regmap_update_bits(priv->regmap, MESON_PCIE_REG0,
>>> +			   MESON_PCIE_POWERDOWN, 0);
>>> +	return 0;
>>> +}
>>> +
>>> +static int phy_axg_pcie_power_off(struct phy *phy)
>>> +{
>>> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
>>> +	int ret;
>>> +
>>> +	ret = phy_power_off(priv->analog);
>>> +	if (ret != 0)
>>> +		return ret;
>>> +
>>> +	regmap_update_bits(priv->regmap, MESON_PCIE_REG0,
>>> +			   MESON_PCIE_POWERDOWN, 1);
>>> +	return 0;
>>> +}
>>> +
>>> +static int phy_axg_pcie_init(struct phy *phy)
>>> +{
>>> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
>>> +	int ret;
>>> +
>>> +	ret = phy_init(priv->analog);
>>> +	if (ret != 0)
>>> +		return ret;
>>> +
>>> +	regmap_write(priv->regmap, MESON_PCIE_REG0, MESON_PCIE_PHY_INIT);
>>> +	return reset_control_reset(priv->reset);
>>> +}
>>> +
>>> +static int phy_axg_pcie_exit(struct phy *phy)
>>> +{
>>> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
>>> +	int ret;
>>> +
>>> +	ret = phy_exit(priv->analog);
>>> +	if (ret != 0)
>>> +		return ret;
>>> +
>>> +	return reset_control_reset(priv->reset);
>>> +}
>>> +
>>> +static int phy_axg_pcie_reset(struct phy *phy)
>>> +{
>>> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
>>> +	int ret = 0;
>>> +
>>> +	ret = phy_reset(priv->analog);
>>> +	if (ret != 0)
>>> +		goto out;
>>> +
>>> +	ret = reset_control_assert(priv->reset);
>>> +	if (ret != 0)
>>> +		goto out;
>>> +	udelay(MESON_PCIE_RESET_DELAY);
>>> +
>>> +	ret = reset_control_deassert(priv->reset);
>>> +	if (ret != 0)
>>> +		goto out;
>>> +	udelay(MESON_PCIE_RESET_DELAY);
>>> +
>>> +out:
>>> +	return ret;
>>> +}
>>> +
>>> +static const struct phy_ops phy_axg_pcie_ops = {
>>> +	.init = phy_axg_pcie_init,
>>> +	.exit = phy_axg_pcie_exit,
>>> +	.power_on = phy_axg_pcie_power_on,
>>> +	.power_off = phy_axg_pcie_power_off,
>>> +	.reset = phy_axg_pcie_reset,
>>> +	.owner = THIS_MODULE,
>>> +};
>>> +
>>> +static int phy_axg_pcie_probe(struct platform_device *pdev)
>>> +{
>>> +	struct phy_provider *pphy;
>>> +	struct device *dev = &pdev->dev;
>>> +	struct phy_axg_pcie_priv *priv;
>>> +	struct device_node *np = dev->of_node;
>>> +	struct resource *res;
>>> +	void __iomem *base;
>>> +	int ret;
>>> +
>>> +	priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
>>> +	if (!priv)
>>> +		return -ENOMEM;
>>> +
>>> +	priv->phy = devm_phy_create(dev, np, &phy_axg_pcie_ops);
>>> +	if (IS_ERR(priv->phy)) {
>>> +		ret = PTR_ERR(priv->phy);
>>> +		if (ret != -EPROBE_DEFER)
>>> +			dev_err(dev, "failed to create PHY\n");
>>> +		return ret;
>>> +	}
>>> +
>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> +	base = devm_ioremap_resource(dev, res);
>>> +	if (IS_ERR(base))
>>> +		return PTR_ERR(base);
>>> +
>>> +	priv->regmap = devm_regmap_init_mmio(dev, base,
>>> +					     &phy_axg_pcie_regmap_conf);
>>> +	if (IS_ERR(priv->regmap))
>>> +		return PTR_ERR(priv->regmap);
>>> +
>>> +	priv->reset = devm_reset_control_array_get(dev, false, false);
>>> +	if (IS_ERR(priv->reset))
>>> +		return PTR_ERR(priv->reset);
>>> +
>>> +	priv->analog = devm_phy_get(dev, "analog");
>>> +	if (IS_ERR(priv->analog))
>>> +		return PTR_ERR(priv->analog);
>>> +
>>> +	phy_set_drvdata(priv->phy, priv);
>>> +	dev_set_drvdata(dev, priv);
>>> +	pphy = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
>>> +
>>> +	return PTR_ERR_OR_ZERO(pphy);
>>> +}
>>> +
>>> +static const struct of_device_id phy_axg_pcie_of_match[] = {
>>> +	{
>>> +		.compatible = "amlogic,axg-pcie-phy",
>>> +	},
>>> +	{ },
>>> +};
>>> +MODULE_DEVICE_TABLE(of, phy_axg_pcie_of_match);
>>> +
>>> +static struct platform_driver phy_axg_pcie_driver = {
>>> +	.probe = phy_axg_pcie_probe,
>>> +	.driver = {
>>> +		.name = "phy-axg-pcie",
>>> +		.of_match_table = phy_axg_pcie_of_match,
>>> +	},
>>> +};
>>> +module_platform_driver(phy_axg_pcie_driver);
>>> +
>>> +MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>");
>>> +MODULE_DESCRIPTION("Amlogic AXG PCIE PHY driver");
>>> +MODULE_LICENSE("GPL v2");
>>>
Neil Armstrong March 5, 2020, 7 a.m. UTC | #18
Hi,

Le 05/03/2020 à 05:56, Kishon Vijay Abraham I a écrit :
> Hi,
> 
> On 04/03/20 6:38 pm, Remi Pommarel wrote:
>> On Wed, Mar 04, 2020 at 04:31:24PM +0530, Kishon Vijay Abraham I wrote:
>>>
>>>
>>> On 24/01/20 4:59 am, Remi Pommarel wrote:
>>>> This adds support for the PCI PHY found in the Amlogic AXG SoC Family.
>>>> This will allow to mutualize code in pci-meson.c between AXG and G12A
>>>> SoC.
>>>>
>>>> This PHY also uses and chains an analog PHY, which on AXG platform
>>>> is needed to have reliable PCIe communication.
>>>
>>> Is the analog PHY an independent block and can be used with other PHYs?
>>
>> It is documented as a separate block yes, but I think it is unlikely
>> that it will be used with other PHYs than the PCIe or the MIPI one of
>> the AXG SoC.
> 
> Shouldn't we then have a single PHY driver instead of chaining PHYs?

The chaining is necessary because the MIPI/PCIe analogi PHY will be reused on
recent platform with similar MIPI DSI PHY, but these platforms have their PCIe PHY
combined with USB3 (see g12a-usb3-pcie combo phy).

Neil

> 
> Thanks
> Kishon
> 
>>
>> Thanks,
>> Remi
>>
>>>
>>> For the patch itself
>>> Acked-by: Kishon Vijay Abraham I <kishon@ti.com>
>>>
>>> Thanks
>>> Kishon
>>>>
>>>> Signed-off-by: Remi Pommarel <repk@triplefau.lt>
>>>> ---
>>>>  drivers/phy/amlogic/Kconfig              |  11 ++
>>>>  drivers/phy/amlogic/Makefile             |   1 +
>>>>  drivers/phy/amlogic/phy-meson-axg-pcie.c | 192 +++++++++++++++++++++++
>>>>  3 files changed, 204 insertions(+)
>>>>  create mode 100644 drivers/phy/amlogic/phy-meson-axg-pcie.c
>>>>
>>>> diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig
>>>> index 8c9cf2403591..71801e30d601 100644
>>>> --- a/drivers/phy/amlogic/Kconfig
>>>> +++ b/drivers/phy/amlogic/Kconfig
>>>> @@ -60,6 +60,17 @@ config PHY_MESON_G12A_USB3_PCIE
>>>>  	  in Meson G12A SoCs.
>>>>  	  If unsure, say N.
>>>>  
>>>> +config PHY_MESON_AXG_PCIE
>>>> +	tristate "Meson AXG PCIE PHY driver"
>>>> +	default ARCH_MESON
>>>> +	depends on OF && (ARCH_MESON || COMPILE_TEST)
>>>> +	select GENERIC_PHY
>>>> +	select REGMAP_MMIO
>>>> +	help
>>>> +	  Enable this to support the Meson MIPI + PCIE PHY found
>>>> +	  in Meson AXG SoCs.
>>>> +	  If unsure, say N.
>>>> +
>>>>  config PHY_MESON_AXG_MIPI_PCIE_ANALOG
>>>>  	tristate "Meson AXG MIPI + PCIE analog PHY driver"
>>>>  	default ARCH_MESON
>>>> diff --git a/drivers/phy/amlogic/Makefile b/drivers/phy/amlogic/Makefile
>>>> index 0aecf92d796a..e2baa133f7af 100644
>>>> --- a/drivers/phy/amlogic/Makefile
>>>> +++ b/drivers/phy/amlogic/Makefile
>>>> @@ -4,4 +4,5 @@ obj-$(CONFIG_PHY_MESON_GXL_USB2)		+= phy-meson-gxl-usb2.o
>>>>  obj-$(CONFIG_PHY_MESON_G12A_USB2)		+= phy-meson-g12a-usb2.o
>>>>  obj-$(CONFIG_PHY_MESON_GXL_USB3)		+= phy-meson-gxl-usb3.o
>>>>  obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE)		+= phy-meson-g12a-usb3-pcie.o
>>>> +obj-$(CONFIG_PHY_MESON_AXG_PCIE)		+= phy-meson-axg-pcie.o
>>>>  obj-$(CONFIG_PHY_MESON_AXG_MIPI_PCIE_ANALOG)	+= phy-meson-axg-mipi-pcie-analog.o
>>>> diff --git a/drivers/phy/amlogic/phy-meson-axg-pcie.c b/drivers/phy/amlogic/phy-meson-axg-pcie.c
>>>> new file mode 100644
>>>> index 000000000000..377ed0dcd0d9
>>>> --- /dev/null
>>>> +++ b/drivers/phy/amlogic/phy-meson-axg-pcie.c
>>>> @@ -0,0 +1,192 @@
>>>> +// SPDX-License-Identifier: GPL-2.0
>>>> +/*
>>>> + * Amlogic AXG PCIE PHY driver
>>>> + *
>>>> + * Copyright (C) 2020 Remi Pommarel <repk@triplefau.lt>
>>>> + */
>>>> +#include <linux/module.h>
>>>> +#include <linux/phy/phy.h>
>>>> +#include <linux/regmap.h>
>>>> +#include <linux/reset.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/bitfield.h>
>>>> +#include <dt-bindings/phy/phy.h>
>>>> +
>>>> +#define MESON_PCIE_REG0 0x00
>>>> +#define		MESON_PCIE_COMMON_CLK	BIT(4)
>>>> +#define		MESON_PCIE_PORT_SEL	GENMASK(3, 2)
>>>> +#define		MESON_PCIE_CLK		BIT(1)
>>>> +#define		MESON_PCIE_POWERDOWN	BIT(0)
>>>> +
>>>> +#define MESON_PCIE_TWO_X1		FIELD_PREP(MESON_PCIE_PORT_SEL, 0x3)
>>>> +#define MESON_PCIE_COMMON_REF_CLK	FIELD_PREP(MESON_PCIE_COMMON_CLK, 0x1)
>>>> +#define MESON_PCIE_PHY_INIT		(MESON_PCIE_TWO_X1 |		\
>>>> +					 MESON_PCIE_COMMON_REF_CLK)
>>>> +#define MESON_PCIE_RESET_DELAY		500
>>>> +
>>>> +struct phy_axg_pcie_priv {
>>>> +	struct phy *phy;
>>>> +	struct phy *analog;
>>>> +	struct regmap *regmap;
>>>> +	struct reset_control *reset;
>>>> +};
>>>> +
>>>> +static const struct regmap_config phy_axg_pcie_regmap_conf = {
>>>> +	.reg_bits = 8,
>>>> +	.val_bits = 32,
>>>> +	.reg_stride = 4,
>>>> +	.max_register = MESON_PCIE_REG0,
>>>> +};
>>>> +
>>>> +static int phy_axg_pcie_power_on(struct phy *phy)
>>>> +{
>>>> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
>>>> +	int ret;
>>>> +
>>>> +	ret = phy_power_on(priv->analog);
>>>> +	if (ret != 0)
>>>> +		return ret;
>>>> +
>>>> +	regmap_update_bits(priv->regmap, MESON_PCIE_REG0,
>>>> +			   MESON_PCIE_POWERDOWN, 0);
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int phy_axg_pcie_power_off(struct phy *phy)
>>>> +{
>>>> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
>>>> +	int ret;
>>>> +
>>>> +	ret = phy_power_off(priv->analog);
>>>> +	if (ret != 0)
>>>> +		return ret;
>>>> +
>>>> +	regmap_update_bits(priv->regmap, MESON_PCIE_REG0,
>>>> +			   MESON_PCIE_POWERDOWN, 1);
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int phy_axg_pcie_init(struct phy *phy)
>>>> +{
>>>> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
>>>> +	int ret;
>>>> +
>>>> +	ret = phy_init(priv->analog);
>>>> +	if (ret != 0)
>>>> +		return ret;
>>>> +
>>>> +	regmap_write(priv->regmap, MESON_PCIE_REG0, MESON_PCIE_PHY_INIT);
>>>> +	return reset_control_reset(priv->reset);
>>>> +}
>>>> +
>>>> +static int phy_axg_pcie_exit(struct phy *phy)
>>>> +{
>>>> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
>>>> +	int ret;
>>>> +
>>>> +	ret = phy_exit(priv->analog);
>>>> +	if (ret != 0)
>>>> +		return ret;
>>>> +
>>>> +	return reset_control_reset(priv->reset);
>>>> +}
>>>> +
>>>> +static int phy_axg_pcie_reset(struct phy *phy)
>>>> +{
>>>> +	struct phy_axg_pcie_priv *priv = phy_get_drvdata(phy);
>>>> +	int ret = 0;
>>>> +
>>>> +	ret = phy_reset(priv->analog);
>>>> +	if (ret != 0)
>>>> +		goto out;
>>>> +
>>>> +	ret = reset_control_assert(priv->reset);
>>>> +	if (ret != 0)
>>>> +		goto out;
>>>> +	udelay(MESON_PCIE_RESET_DELAY);
>>>> +
>>>> +	ret = reset_control_deassert(priv->reset);
>>>> +	if (ret != 0)
>>>> +		goto out;
>>>> +	udelay(MESON_PCIE_RESET_DELAY);
>>>> +
>>>> +out:
>>>> +	return ret;
>>>> +}
>>>> +
>>>> +static const struct phy_ops phy_axg_pcie_ops = {
>>>> +	.init = phy_axg_pcie_init,
>>>> +	.exit = phy_axg_pcie_exit,
>>>> +	.power_on = phy_axg_pcie_power_on,
>>>> +	.power_off = phy_axg_pcie_power_off,
>>>> +	.reset = phy_axg_pcie_reset,
>>>> +	.owner = THIS_MODULE,
>>>> +};
>>>> +
>>>> +static int phy_axg_pcie_probe(struct platform_device *pdev)
>>>> +{
>>>> +	struct phy_provider *pphy;
>>>> +	struct device *dev = &pdev->dev;
>>>> +	struct phy_axg_pcie_priv *priv;
>>>> +	struct device_node *np = dev->of_node;
>>>> +	struct resource *res;
>>>> +	void __iomem *base;
>>>> +	int ret;
>>>> +
>>>> +	priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
>>>> +	if (!priv)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	priv->phy = devm_phy_create(dev, np, &phy_axg_pcie_ops);
>>>> +	if (IS_ERR(priv->phy)) {
>>>> +		ret = PTR_ERR(priv->phy);
>>>> +		if (ret != -EPROBE_DEFER)
>>>> +			dev_err(dev, "failed to create PHY\n");
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>> +	base = devm_ioremap_resource(dev, res);
>>>> +	if (IS_ERR(base))
>>>> +		return PTR_ERR(base);
>>>> +
>>>> +	priv->regmap = devm_regmap_init_mmio(dev, base,
>>>> +					     &phy_axg_pcie_regmap_conf);
>>>> +	if (IS_ERR(priv->regmap))
>>>> +		return PTR_ERR(priv->regmap);
>>>> +
>>>> +	priv->reset = devm_reset_control_array_get(dev, false, false);
>>>> +	if (IS_ERR(priv->reset))
>>>> +		return PTR_ERR(priv->reset);
>>>> +
>>>> +	priv->analog = devm_phy_get(dev, "analog");
>>>> +	if (IS_ERR(priv->analog))
>>>> +		return PTR_ERR(priv->analog);
>>>> +
>>>> +	phy_set_drvdata(priv->phy, priv);
>>>> +	dev_set_drvdata(dev, priv);
>>>> +	pphy = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
>>>> +
>>>> +	return PTR_ERR_OR_ZERO(pphy);
>>>> +}
>>>> +
>>>> +static const struct of_device_id phy_axg_pcie_of_match[] = {
>>>> +	{
>>>> +		.compatible = "amlogic,axg-pcie-phy",
>>>> +	},
>>>> +	{ },
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, phy_axg_pcie_of_match);
>>>> +
>>>> +static struct platform_driver phy_axg_pcie_driver = {
>>>> +	.probe = phy_axg_pcie_probe,
>>>> +	.driver = {
>>>> +		.name = "phy-axg-pcie",
>>>> +		.of_match_table = phy_axg_pcie_of_match,
>>>> +	},
>>>> +};
>>>> +module_platform_driver(phy_axg_pcie_driver);
>>>> +
>>>> +MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>");
>>>> +MODULE_DESCRIPTION("Amlogic AXG PCIE PHY driver");
>>>> +MODULE_LICENSE("GPL v2");
>>>>