2020-09-07 07:37:20

by Neil Armstrong

[permalink] [raw]
Subject: [PATCH 0/3] phy: amlogic: add MIPI DSI function to analog MIPI+PCIe PHY

The AXG Analog MIPI-DSI PHY also provides functions to the PCIe PHY,
thus we need to have inclusive support for both interfaces at runtime.

This fixes the regmap get from parent node, removes cell param
to select a mode and implement runtime configuration & power on/off
for both functions since they are not exclusive.

Neil Armstrong (3):
dt-bindings: phy: amlogic,meson-axg-mipi-pcie-analog: remove reg
attribute
dt-bindings: phy: amlogic,meson-axg-mipi-pcie-analog: remove phy cell
parameter
phy: amlogic: phy-meson-axg-mipi-pcie-analog: add support for MIPI DSI
analog

.../amlogic,meson-axg-mipi-pcie-analog.yaml | 8 +-
drivers/phy/amlogic/Kconfig | 1 +
.../amlogic/phy-meson-axg-mipi-pcie-analog.c | 204 ++++++++++++------
3 files changed, 138 insertions(+), 75 deletions(-)

--
2.22.0


2020-09-07 07:37:29

by Neil Armstrong

[permalink] [raw]
Subject: [PATCH 3/3] phy: amlogic: phy-meson-axg-mipi-pcie-analog: add support for MIPI DSI analog

The AXG Analog MIPI-DSI PHY also provides functions to the PCIe PHY,
thus we need to have inclusive support for both interfaces at runtime.

This fixes the regmap get from parent node, removes cell param
to select a mode and implement runtime configuration & power on/off
for both functions since they are not exclusive.

Signed-off-by: Neil Armstrong <[email protected]>
---
drivers/phy/amlogic/Kconfig | 1 +
.../amlogic/phy-meson-axg-mipi-pcie-analog.c | 204 ++++++++++++------
2 files changed, 136 insertions(+), 69 deletions(-)

diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig
index 99e8a4c7f1f3..db5d0cd757e3 100644
--- a/drivers/phy/amlogic/Kconfig
+++ b/drivers/phy/amlogic/Kconfig
@@ -66,6 +66,7 @@ config PHY_MESON_AXG_MIPI_PCIE_ANALOG
depends on OF && (ARCH_MESON || COMPILE_TEST)
select GENERIC_PHY
select REGMAP_MMIO
+ select GENERIC_PHY_MIPI_DPHY
help
Enable this to support the Meson MIPI + PCIE analog PHY
found in Meson AXG SoCs.
diff --git a/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
index 1431cbf885e1..6eb21551bdd9 100644
--- a/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
+++ b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
@@ -4,9 +4,13 @@
*
* Copyright (C) 2019 Remi Pommarel <[email protected]>
*/
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/phy/phy.h>
#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
#include <dt-bindings/phy/phy.h>

@@ -14,10 +18,10 @@
#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_CNTL0_DIF_REF_CTL1 GENMASK(25, 16)
+#define HHI_MIPI_CNTL0_DIF_REF_CTL0 GENMASK(15, 0)

-#define HHI_MIPI_CNTL1 0x01
+#define HHI_MIPI_CNTL1 0x04
#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)
@@ -25,100 +29,170 @@
#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 0x08
#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_CH_EN GENMASK(15, 11)
#define HHI_MIPI_CNTL2_CH0_LP_CTL GENMASK(10, 1)

+#define DSI_LANE_0 (1 << 4)
+#define DSI_LANE_1 (1 << 3)
+#define DSI_LANE_CLK (1 << 2)
+#define DSI_LANE_2 (1 << 1)
+#define DSI_LANE_3 (1 << 0)
+#define DSI_LANE_MASK (0x1F)
+
struct phy_axg_mipi_pcie_analog_priv {
struct phy *phy;
- unsigned int mode;
struct regmap *regmap;
+ bool dsi_configured;
+ bool dsi_enabled;
+ bool powered;
+ struct phy_configure_opts_mipi_dphy config;
};

-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 void phy_bandgap_enable(struct phy_axg_mipi_pcie_analog_priv *priv)
+{
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
+ HHI_MIPI_CNTL0_BANDGAP, HHI_MIPI_CNTL0_BANDGAP);

-static int phy_axg_mipi_pcie_analog_power_on(struct phy *phy)
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
+ HHI_MIPI_CNTL0_ENABLE, HHI_MIPI_CNTL0_ENABLE);
+}
+
+static void phy_bandgap_disable(struct phy_axg_mipi_pcie_analog_priv *priv)
{
- struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
+ 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);
+}

- /* MIPI not supported yet */
- if (priv->mode != PHY_TYPE_PCIE)
- return -EINVAL;
+static void phy_dsi_analog_enable(struct phy_axg_mipi_pcie_analog_priv *priv)
+{
+ u32 reg;

regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
- HHI_MIPI_CNTL0_BANDGAP, HHI_MIPI_CNTL0_BANDGAP);
+ HHI_MIPI_CNTL0_DIF_REF_CTL1,
+ FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL1, 0x1b8));
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
+ BIT(31), BIT(31));
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
+ HHI_MIPI_CNTL0_DIF_REF_CTL0,
+ FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL0, 0x8));
+
+ regmap_write(priv->regmap, HHI_MIPI_CNTL1, 0x001e);
+
+ regmap_write(priv->regmap, HHI_MIPI_CNTL2,
+ (0x26e0 << 16) | (0x459 << 0));
+
+ reg = DSI_LANE_CLK;
+ switch (priv->config.lanes) {
+ case 4:
+ reg |= DSI_LANE_3;
+ fallthrough;
+ case 3:
+ reg |= DSI_LANE_2;
+ fallthrough;
+ case 2:
+ reg |= DSI_LANE_1;
+ fallthrough;
+ case 1:
+ reg |= DSI_LANE_0;
+ break;
+ default:
+ reg = 0;
+ }
+
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL2,
+ HHI_MIPI_CNTL2_CH_EN,
+ FIELD_PREP(HHI_MIPI_CNTL2_CH_EN, reg));
+
+ priv->dsi_enabled = true;
+}

+static void phy_dsi_analog_disable(struct phy_axg_mipi_pcie_analog_priv *priv)
+{
regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
- HHI_MIPI_CNTL0_ENABLE, HHI_MIPI_CNTL0_ENABLE);
- return 0;
+ HHI_MIPI_CNTL0_DIF_REF_CTL1,
+ FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL1, 0));
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, BIT(31), 0);
+ regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
+ HHI_MIPI_CNTL0_DIF_REF_CTL1, 0);
+
+ regmap_write(priv->regmap, HHI_MIPI_CNTL1, 0x6);
+
+ regmap_write(priv->regmap, HHI_MIPI_CNTL2, 0x00200000);
+
+ priv->dsi_enabled = false;
}

-static int phy_axg_mipi_pcie_analog_power_off(struct phy *phy)
+static int phy_axg_mipi_pcie_analog_configure(struct phy *phy,
+ union phy_configure_opts *opts)
{
struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
+ int ret;

- /* MIPI not supported yet */
- if (priv->mode != PHY_TYPE_PCIE)
- return -EINVAL;
+ ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy);
+ if (ret)
+ return ret;
+
+ memcpy(&priv->config, opts, sizeof(priv->config));
+
+ priv->dsi_configured = true;
+
+ /* If PHY was already powered on, setup the DSI analog part */
+ if (priv->powered) {
+ /* If reconfiguring, disable & reconfigure */
+ if (priv->dsi_enabled)
+ phy_dsi_analog_disable(priv);
+
+ usleep_range(100, 200);
+
+ phy_dsi_analog_enable(priv);
+ }

- 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)
+static int phy_axg_mipi_pcie_analog_power_on(struct phy *phy)
{
+ struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
+
+ phy_bandgap_enable(priv);
+
+ if (priv->dsi_configured)
+ phy_dsi_analog_enable(priv);
+
+ priv->powered = true;
+
return 0;
}

-static int phy_axg_mipi_pcie_analog_exit(struct phy *phy)
+static int phy_axg_mipi_pcie_analog_power_off(struct phy *phy)
{
+ struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
+
+ phy_bandgap_disable(priv);
+
+ if (priv->dsi_enabled)
+ phy_dsi_analog_disable(priv);
+
+ priv->powered = false;
+
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,
+ .configure = phy_axg_mipi_pcie_analog_configure,
.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;
@@ -126,27 +200,20 @@ static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev)
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);
+ /* Get the hhi system controller node */
+ map = syscon_node_to_regmap(of_get_parent(dev->of_node));
if (IS_ERR(map)) {
- dev_err(dev, "failed to get HHI regmap\n");
+ 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);
@@ -160,8 +227,7 @@ static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev)
phy_set_drvdata(priv->phy, priv);
dev_set_drvdata(dev, priv);

- phy = devm_of_phy_provider_register(dev,
- phy_axg_mipi_pcie_analog_xlate);
+ phy = devm_of_phy_provider_register(dev, of_phy_simple_xlate);

return PTR_ERR_OR_ZERO(phy);
}
--
2.22.0

2020-09-07 07:37:58

by Neil Armstrong

[permalink] [raw]
Subject: [PATCH 2/3] dt-bindings: phy: amlogic,meson-axg-mipi-pcie-analog: remove phy cell parameter

The Amlogic AXG MIPI + PCIe Analog PHY provides function for both PCIe and
MIPI DSI at the same time, and is not exclusive.

Thus remove the invalid phy cell parameter.

Signed-off-by: Neil Armstrong <[email protected]>
---
.../bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
index a9040aa387cf..148618b51b24 100644
--- a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
+++ b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
@@ -14,7 +14,7 @@ properties:
const: amlogic,axg-mipi-pcie-analog-phy

"#phy-cells":
- const: 1
+ const: 0

required:
- compatible
@@ -27,5 +27,5 @@ examples:
mpphy: phy@0 {
compatible = "amlogic,axg-mipi-pcie-analog-phy";
reg = <0x0 0xc>;
- #phy-cells = <1>;
+ #phy-cells = <0>;
};
--
2.22.0

2020-09-07 07:39:39

by Neil Armstrong

[permalink] [raw]
Subject: [PATCH 1/3] dt-bindings: phy: amlogic,meson-axg-mipi-pcie-analog: remove reg attribute

The Amlogic AXG MIPI + PCIe Analog PHY should be a subnode of the hhi mfd
node like the axg-clkc node.

Thus the reg attribute is not needed.

Signed-off-by: Neil Armstrong <[email protected]>
---
.../bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml | 4 ----
1 file changed, 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
index 18c1ec5e19ad..a9040aa387cf 100644
--- a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
+++ b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
@@ -13,15 +13,11 @@ properties:
compatible:
const: amlogic,axg-mipi-pcie-analog-phy

- reg:
- maxItems: 1
-
"#phy-cells":
const: 1

required:
- compatible
- - reg
- "#phy-cells"

additionalProperties: false
--
2.22.0

2020-09-08 19:51:03

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH 1/3] dt-bindings: phy: amlogic, meson-axg-mipi-pcie-analog: remove reg attribute

On Mon, 07 Sep 2020 09:34:00 +0200, Neil Armstrong wrote:
> The Amlogic AXG MIPI + PCIe Analog PHY should be a subnode of the hhi mfd
> node like the axg-clkc node.
>
> Thus the reg attribute is not needed.
>
> Signed-off-by: Neil Armstrong <[email protected]>
> ---
> .../bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml | 4 ----
> 1 file changed, 4 deletions(-)
>


My bot found errors running 'make dt_binding_check' on your patch:

/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.example.dt.yaml: phy@0: 'reg' does not match any of the regexes: 'pinctrl-[0-9]+'
From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml


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

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure dt-schema is up to date:

pip3 install git+https://github.com/devicetree-org/dt-schema.git@master --upgrade

Please check and re-submit.

2020-09-08 19:53:18

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH 1/3] dt-bindings: phy: amlogic,meson-axg-mipi-pcie-analog: remove reg attribute

On Mon, Sep 07, 2020 at 09:34:00AM +0200, Neil Armstrong wrote:
> The Amlogic AXG MIPI + PCIe Analog PHY should be a subnode of the hhi mfd
> node like the axg-clkc node.
>
> Thus the reg attribute is not needed.

If the phy registers have an address then it should remain even if Linux
happens to not care. The exception is if the registers are all
interleaved with other stuff.

>
> Signed-off-by: Neil Armstrong <[email protected]>
> ---
> .../bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml | 4 ----
> 1 file changed, 4 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
> index 18c1ec5e19ad..a9040aa387cf 100644
> --- a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
> +++ b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
> @@ -13,15 +13,11 @@ properties:
> compatible:
> const: amlogic,axg-mipi-pcie-analog-phy
>
> - reg:
> - maxItems: 1
> -
> "#phy-cells":
> const: 1
>
> required:
> - compatible
> - - reg
> - "#phy-cells"
>
> additionalProperties: false
> --
> 2.22.0
>

2020-09-08 20:26:59

by Remi Pommarel

[permalink] [raw]
Subject: Re: [PATCH 3/3] phy: amlogic: phy-meson-axg-mipi-pcie-analog: add support for MIPI DSI analog

Hi,

On Mon, Sep 07, 2020 at 09:34:02AM +0200, Neil Armstrong wrote:
> The AXG Analog MIPI-DSI PHY also provides functions to the PCIe PHY,
> thus we need to have inclusive support for both interfaces at runtime.
>
> This fixes the regmap get from parent node, removes cell param
> to select a mode and implement runtime configuration & power on/off
> for both functions since they are not exclusive.
>
> Signed-off-by: Neil Armstrong <[email protected]>
> ---
> drivers/phy/amlogic/Kconfig | 1 +
> .../amlogic/phy-meson-axg-mipi-pcie-analog.c | 204 ++++++++++++------
> 2 files changed, 136 insertions(+), 69 deletions(-)
>
> diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig
> index 99e8a4c7f1f3..db5d0cd757e3 100644
> --- a/drivers/phy/amlogic/Kconfig
> +++ b/drivers/phy/amlogic/Kconfig
> @@ -66,6 +66,7 @@ config PHY_MESON_AXG_MIPI_PCIE_ANALOG
> depends on OF && (ARCH_MESON || COMPILE_TEST)
> select GENERIC_PHY
> select REGMAP_MMIO
> + select GENERIC_PHY_MIPI_DPHY
> help
> Enable this to support the Meson MIPI + PCIE analog PHY
> found in Meson AXG SoCs.
> diff --git a/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> index 1431cbf885e1..6eb21551bdd9 100644
> --- a/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> +++ b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
> @@ -4,9 +4,13 @@
> *
> * Copyright (C) 2019 Remi Pommarel <[email protected]>
> */
> +#include <linux/bitfield.h>
> +#include <linux/bitops.h>
> #include <linux/module.h>
> #include <linux/phy/phy.h>
> #include <linux/regmap.h>
> +#include <linux/delay.h>
> +#include <linux/mfd/syscon.h>
> #include <linux/platform_device.h>
> #include <dt-bindings/phy/phy.h>
>
> @@ -14,10 +18,10 @@
> #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_CNTL0_DIF_REF_CTL1 GENMASK(25, 16)
> +#define HHI_MIPI_CNTL0_DIF_REF_CTL0 GENMASK(15, 0)
>
> -#define HHI_MIPI_CNTL1 0x01
> +#define HHI_MIPI_CNTL1 0x04
> #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)
> @@ -25,100 +29,170 @@
> #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 0x08
> #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_CH_EN GENMASK(15, 11)
> #define HHI_MIPI_CNTL2_CH0_LP_CTL GENMASK(10, 1)
>
> +#define DSI_LANE_0 (1 << 4)
> +#define DSI_LANE_1 (1 << 3)
> +#define DSI_LANE_CLK (1 << 2)
> +#define DSI_LANE_2 (1 << 1)
> +#define DSI_LANE_3 (1 << 0)
> +#define DSI_LANE_MASK (0x1F)
> +
> struct phy_axg_mipi_pcie_analog_priv {
> struct phy *phy;
> - unsigned int mode;
> struct regmap *regmap;
> + bool dsi_configured;
> + bool dsi_enabled;
> + bool powered;
> + struct phy_configure_opts_mipi_dphy config;
> };
>
> -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 void phy_bandgap_enable(struct phy_axg_mipi_pcie_analog_priv *priv)
> +{
> + regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> + HHI_MIPI_CNTL0_BANDGAP, HHI_MIPI_CNTL0_BANDGAP);
>
> -static int phy_axg_mipi_pcie_analog_power_on(struct phy *phy)
> + regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> + HHI_MIPI_CNTL0_ENABLE, HHI_MIPI_CNTL0_ENABLE);
> +}
> +
> +static void phy_bandgap_disable(struct phy_axg_mipi_pcie_analog_priv *priv)
> {
> - struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
> + 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);
> +}
>
> - /* MIPI not supported yet */
> - if (priv->mode != PHY_TYPE_PCIE)
> - return -EINVAL;
> +static void phy_dsi_analog_enable(struct phy_axg_mipi_pcie_analog_priv *priv)
> +{
> + u32 reg;
>
> regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> - HHI_MIPI_CNTL0_BANDGAP, HHI_MIPI_CNTL0_BANDGAP);
> + HHI_MIPI_CNTL0_DIF_REF_CTL1,
> + FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL1, 0x1b8));
> + regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> + BIT(31), BIT(31));
> + regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> + HHI_MIPI_CNTL0_DIF_REF_CTL0,
> + FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL0, 0x8));
> +
> + regmap_write(priv->regmap, HHI_MIPI_CNTL1, 0x001e);
> +
> + regmap_write(priv->regmap, HHI_MIPI_CNTL2,
> + (0x26e0 << 16) | (0x459 << 0));
> +
> + reg = DSI_LANE_CLK;
> + switch (priv->config.lanes) {
> + case 4:
> + reg |= DSI_LANE_3;
> + fallthrough;
> + case 3:
> + reg |= DSI_LANE_2;
> + fallthrough;
> + case 2:
> + reg |= DSI_LANE_1;
> + fallthrough;
> + case 1:
> + reg |= DSI_LANE_0;
> + break;
> + default:
> + reg = 0;
> + }
> +
> + regmap_update_bits(priv->regmap, HHI_MIPI_CNTL2,
> + HHI_MIPI_CNTL2_CH_EN,
> + FIELD_PREP(HHI_MIPI_CNTL2_CH_EN, reg));
> +
> + priv->dsi_enabled = true;
> +}
>
> +static void phy_dsi_analog_disable(struct phy_axg_mipi_pcie_analog_priv *priv)
> +{
> regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> - HHI_MIPI_CNTL0_ENABLE, HHI_MIPI_CNTL0_ENABLE);
> - return 0;
> + HHI_MIPI_CNTL0_DIF_REF_CTL1,
> + FIELD_PREP(HHI_MIPI_CNTL0_DIF_REF_CTL1, 0));
> + regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0, BIT(31), 0);
> + regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
> + HHI_MIPI_CNTL0_DIF_REF_CTL1, 0);
> +
> + regmap_write(priv->regmap, HHI_MIPI_CNTL1, 0x6);
> +
> + regmap_write(priv->regmap, HHI_MIPI_CNTL2, 0x00200000);
> +
> + priv->dsi_enabled = false;
> }
>
> -static int phy_axg_mipi_pcie_analog_power_off(struct phy *phy)
> +static int phy_axg_mipi_pcie_analog_configure(struct phy *phy,
> + union phy_configure_opts *opts)
> {
> struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
> + int ret;
>
> - /* MIPI not supported yet */
> - if (priv->mode != PHY_TYPE_PCIE)
> - return -EINVAL;
> + ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy);
> + if (ret)
> + return ret;
> +
> + memcpy(&priv->config, opts, sizeof(priv->config));
> +
> + priv->dsi_configured = true;
> +
> + /* If PHY was already powered on, setup the DSI analog part */
> + if (priv->powered) {
> + /* If reconfiguring, disable & reconfigure */
> + if (priv->dsi_enabled)
> + phy_dsi_analog_disable(priv);
> +
> + usleep_range(100, 200);
> +
> + phy_dsi_analog_enable(priv);
> + }
>
> - 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)
> +static int phy_axg_mipi_pcie_analog_power_on(struct phy *phy)
> {
> + struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
> +
> + phy_bandgap_enable(priv);
> +
> + if (priv->dsi_configured)
> + phy_dsi_analog_enable(priv);
> +
> + priv->powered = true;
> +
> return 0;
> }
>
> -static int phy_axg_mipi_pcie_analog_exit(struct phy *phy)
> +static int phy_axg_mipi_pcie_analog_power_off(struct phy *phy)
> {
> + struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
> +
> + phy_bandgap_disable(priv);
> +
> + if (priv->dsi_enabled)
> + phy_dsi_analog_disable(priv);
> +
> + priv->powered = false;
> +
> 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,
> + .configure = phy_axg_mipi_pcie_analog_configure,
> .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;
> @@ -126,27 +200,20 @@ static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev)
> 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);
> + /* Get the hhi system controller node */
> + map = syscon_node_to_regmap(of_get_parent(dev->of_node));
> if (IS_ERR(map)) {
> - dev_err(dev, "failed to get HHI regmap\n");
> + 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);
> @@ -160,8 +227,7 @@ static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev)
> phy_set_drvdata(priv->phy, priv);
> dev_set_drvdata(dev, priv);
>
> - phy = devm_of_phy_provider_register(dev,
> - phy_axg_mipi_pcie_analog_xlate);
> + phy = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
>
> return PTR_ERR_OR_ZERO(phy);
> }

Thanks for that. As discussed offline, and contrary to what was discussed
here [0], syscon is in fact used here to avoid collision with the hiu
mfd.

FWIW,

Reviewed-by: Remi Pommarel <[email protected]>

[0] https://patchwork.ozlabs.org/project/linux-pci/patch/[email protected]/#2331686

--
Remi

2020-09-09 07:34:37

by Neil Armstrong

[permalink] [raw]
Subject: Re: [PATCH 1/3] dt-bindings: phy: amlogic,meson-axg-mipi-pcie-analog: remove reg attribute

Hi,

On 08/09/2020 21:50, Rob Herring wrote:
> On Mon, Sep 07, 2020 at 09:34:00AM +0200, Neil Armstrong wrote:
>> The Amlogic AXG MIPI + PCIe Analog PHY should be a subnode of the hhi mfd
>> node like the axg-clkc node.
>>
>> Thus the reg attribute is not needed.
>
> If the phy registers have an address then it should remain even if Linux
> happens to not care. The exception is if the registers are all
> interleaved with other stuff.

This is not really a question about linux using it or not.

The PHY registers happens to be at the beginning of a large zone containing
interleaved system registers (mainly clocks, power management, PHY control..).

The goal is to model it the same way as the other "features" of this zone,
like Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt
and Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml
and have a coherent bindings scheme.

Neil

>
>>
>> Signed-off-by: Neil Armstrong <[email protected]>
>> ---
>> .../bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml | 4 ----
>> 1 file changed, 4 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
>> index 18c1ec5e19ad..a9040aa387cf 100644
>> --- a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
>> +++ b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
>> @@ -13,15 +13,11 @@ properties:
>> compatible:
>> const: amlogic,axg-mipi-pcie-analog-phy
>>
>> - reg:
>> - maxItems: 1
>> -
>> "#phy-cells":
>> const: 1
>>
>> required:
>> - compatible
>> - - reg
>> - "#phy-cells"
>>
>> additionalProperties: false
>> --
>> 2.22.0
>>

2020-09-15 22:15:02

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH 2/3] dt-bindings: phy: amlogic, meson-axg-mipi-pcie-analog: remove phy cell parameter

On Mon, 07 Sep 2020 09:34:01 +0200, Neil Armstrong wrote:
> The Amlogic AXG MIPI + PCIe Analog PHY provides function for both PCIe and
> MIPI DSI at the same time, and is not exclusive.
>
> Thus remove the invalid phy cell parameter.
>
> Signed-off-by: Neil Armstrong <[email protected]>
> ---
> .../bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>

Acked-by: Rob Herring <[email protected]>