Subject: [RFC PATCH 0/4] Add RGB ttl connection on rockchip phy

The rockchip phy can be convigured in ttl mode. The phy is shared
between lvds, dsi, ttl. The configuration that now I'm able to support
has the display output on some set of pins on standard vop output
and a set of pins using the ttl phy. The solution is not clean as I
would like to have because some register that are used to enable
the TTL, are in the same register area of the dsi controller.
In order to test I must add the following

dsi_dphy: phy@ff2e0000 {

reg = <0x0 0xff2e0000 0x0 0x10000>,
<0x0 0xff450000 0x0 0x10000>;
...
}

The problem here is the second region I have added is the same of
dsi logic. Only one register is needed by the the phy driver

Michael Trimarchi (4):
phy: add PHY_MODE_TTL
phy: rockchip: Add inno_is_valid_phy_mode
phy: rockchip: Implement TTY phy mode
drm/rockchip: rgb: Add dphy connection to rgb output

drivers/gpu/drm/rockchip/rockchip_rgb.c | 18 +++++
.../phy/rockchip/phy-rockchip-inno-dsidphy.c | 72 +++++++++++++++++++
include/linux/phy/phy.h | 3 +-
3 files changed, 92 insertions(+), 1 deletion(-)

--
2.34.1


Subject: [RFC PATCH 2/4] phy: rockchip: Add inno_is_valid_phy_mode

The function is used to avoid to enable clock on the hardware
if the mode requested is invalid

Signed-off-by: Michael Trimarchi <[email protected]>
---
.../phy/rockchip/phy-rockchip-inno-dsidphy.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)

diff --git a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
index 630e01b5c19b..644cf73cfd53 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
@@ -217,6 +217,20 @@ static void phy_update_bits(struct inno_dsidphy *inno,
writel(tmp, inno->phy_base + reg);
}

+static int inno_is_valid_phy_mode(struct inno_dsidphy *inno)
+{
+ switch (inno->mode) {
+ case PHY_MODE_MIPI_DPHY:
+ break;
+ case PHY_MODE_LVDS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+};
+
static unsigned long inno_dsidphy_pll_calc_rate(struct inno_dsidphy *inno,
unsigned long rate)
{
@@ -495,6 +509,11 @@ static void inno_dsidphy_lvds_mode_enable(struct inno_dsidphy *inno)
static int inno_dsidphy_power_on(struct phy *phy)
{
struct inno_dsidphy *inno = phy_get_drvdata(phy);
+ int ret = 0;
+
+ ret = inno_is_valid_phy_mode(inno);
+ if (ret)
+ return ret;

clk_prepare_enable(inno->pclk_phy);
clk_prepare_enable(inno->ref_clk);
--
2.34.1

Subject: [RFC PATCH 1/4] phy: add PHY_MODE_TTL

There are combo phys out there that can be switched between doing
dsi, lvds, and ttl. So add a mode definition for it.

Signed-off-by: Michael Trimarchi <[email protected]>
---
include/linux/phy/phy.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index b1413757fcc3..87ae8c27ec57 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -42,7 +42,8 @@ enum phy_mode {
PHY_MODE_MIPI_DPHY,
PHY_MODE_SATA,
PHY_MODE_LVDS,
- PHY_MODE_DP
+ PHY_MODE_DP,
+ PHY_MODE_TTL
};

enum phy_media {
--
2.34.1

Subject: [RFC PATCH 3/4] phy: rockchip: Implement TTY phy mode

The rockchip phy can be programmed in 3 modes:
- dsi
- lvds
- ttl

For instance in px30 there are two sets of rgb interface pins m0 and m1.
The logic can go outside from the VOP using m0 set or go outside using
the m1 set and the ttl logic enable. There are combination where a set
of pin can be taken from m1 and m0 where all the two path are enabled.

dsi and ttl enable share one register in their register area. Simple
implementation is overlap the area where we want access the register

Signed-off-by: Michael Trimarchi <[email protected]>
---
.../phy/rockchip/phy-rockchip-inno-dsidphy.c | 53 +++++++++++++++++++
1 file changed, 53 insertions(+)

diff --git a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
index 644cf73cfd53..0af50d2e0402 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
@@ -217,6 +217,17 @@ static void phy_update_bits(struct inno_dsidphy *inno,
writel(tmp, inno->phy_base + reg);
}

+static void host_update_bits(struct inno_dsidphy *inno,
+ u32 reg, u32 mask, u32 val)
+{
+ unsigned int tmp, orig;
+
+ orig = readl(inno->host_base + reg);
+ tmp = orig & ~mask;
+ tmp |= val & mask;
+ writel(tmp, inno->host_base + reg);
+}
+
static int inno_is_valid_phy_mode(struct inno_dsidphy *inno)
{
switch (inno->mode) {
@@ -224,6 +235,10 @@ static int inno_is_valid_phy_mode(struct inno_dsidphy *inno)
break;
case PHY_MODE_LVDS:
break;
+ case PHY_MODE_TTL:
+ if (IS_ERR(inno->host_base))
+ return -EINVAL;
+ break;
default:
return -EINVAL;
}
@@ -506,6 +521,32 @@ static void inno_dsidphy_lvds_mode_enable(struct inno_dsidphy *inno)
LVDS_DATA_LANE2_EN | LVDS_DATA_LANE3_EN);
}

+static void inno_dsidphy_ttl_mode_enable(struct inno_dsidphy *inno)
+{
+ /* Select TTL mode */
+ phy_update_bits(inno, REGISTER_PART_LVDS, 0x03,
+ MODE_ENABLE_MASK, TTL_MODE_ENABLE);
+ /* Reset digital logic */
+ phy_update_bits(inno, REGISTER_PART_LVDS, 0x00,
+ LVDS_DIGITAL_INTERNAL_RESET_MASK,
+ LVDS_DIGITAL_INTERNAL_RESET_ENABLE);
+ udelay(1);
+ phy_update_bits(inno, REGISTER_PART_LVDS, 0x00,
+ LVDS_DIGITAL_INTERNAL_RESET_MASK,
+ LVDS_DIGITAL_INTERNAL_RESET_DISABLE);
+ /* Enable digital logic */
+ phy_update_bits(inno, REGISTER_PART_LVDS, 0x01,
+ LVDS_DIGITAL_INTERNAL_ENABLE_MASK,
+ LVDS_DIGITAL_INTERNAL_ENABLE);
+ /* Enable analog driver */
+ phy_update_bits(inno, REGISTER_PART_LVDS, 0x0b,
+ LVDS_LANE_EN_MASK, LVDS_CLK_LANE_EN |
+ LVDS_DATA_LANE0_EN | LVDS_DATA_LANE1_EN |
+ LVDS_DATA_LANE2_EN | LVDS_DATA_LANE3_EN);
+ /* Enable for clk lane in TTL mode */
+ host_update_bits(inno, DSI_PHY_RSTZ, PHY_ENABLECLK, PHY_ENABLECLK);
+}
+
static int inno_dsidphy_power_on(struct phy *phy)
{
struct inno_dsidphy *inno = phy_get_drvdata(phy);
@@ -533,6 +574,9 @@ static int inno_dsidphy_power_on(struct phy *phy)
case PHY_MODE_LVDS:
inno_dsidphy_lvds_mode_enable(inno);
break;
+ case PHY_MODE_TTL:
+ inno_dsidphy_ttl_mode_enable(inno);
+ break;
default:
return -EINVAL;
}
@@ -561,6 +605,10 @@ static int inno_dsidphy_power_off(struct phy *phy)
LVDS_PLL_POWER_MASK | LVDS_BANDGAP_POWER_MASK,
LVDS_PLL_POWER_OFF | LVDS_BANDGAP_POWER_DOWN);

+ /* Disable for clk lane in TTL mode */
+ if (!IS_ERR(inno->host_base))
+ host_update_bits(inno, DSI_PHY_RSTZ, PHY_ENABLECLK, 0);
+
pm_runtime_put(inno->dev);
clk_disable_unprepare(inno->ref_clk);
clk_disable_unprepare(inno->pclk_phy);
@@ -576,6 +624,7 @@ static int inno_dsidphy_set_mode(struct phy *phy, enum phy_mode mode,
switch (mode) {
case PHY_MODE_MIPI_DPHY:
case PHY_MODE_LVDS:
+ case PHY_MODE_TTL:
inno->mode = mode;
break;
default:
@@ -630,6 +679,10 @@ static int inno_dsidphy_probe(struct platform_device *pdev)
if (IS_ERR(inno->phy_base))
return PTR_ERR(inno->phy_base);

+ inno->host_base = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(inno->host_base))
+ dev_warn(dev, "TTL mode is not supported\n");
+
inno->ref_clk = devm_clk_get(dev, "ref");
if (IS_ERR(inno->ref_clk)) {
ret = PTR_ERR(inno->ref_clk);
--
2.34.1

Subject: [RFC PATCH 4/4] drm/rockchip: rgb: Add dphy connection to rgb output

Dispite the commit 1f0f015151727, the rgb output has an option
to allow to sent the output pin using the dsi/lvds/ttl logic.
The only way to do and stay on the same design is let the
rockchip_rgb block to grab the handle if it is present and
enable it. The present of this handle depends on dts configuration

I have a full working example with an hardware with mixed lines
on direct logic and using the phy, with the follow dts example:

panel: panel {
compatible = "panel-dpi";
...
panel-timing {
clock-frequency = <30000000>;
...
};

port {
panel_rgb_in: endpoint {
remote-endpoint = <&vopb_out_rgb>;
};
};
};

&vopb_out {
vopb_out_rgb: endpoint@2 {
reg = <2>;
remote-endpoint = <&panel_rgb_in>;
};
};

&vopb {
status = "okay";
pinctrl-names = "default", "sleep";
pinctrl-0 = <&lcdc_rgb_pins>;
pinctrl-1 = <&lcdc_sleep_pins>;

phys = <&dsi_dphy>;
phy-names = "dphy";
};

Signed-off-by: Michael Trimarchi <[email protected]>
---
drivers/gpu/drm/rockchip/rockchip_rgb.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c
index 75eb7cca3d82..c725774a0f40 100644
--- a/drivers/gpu/drm/rockchip/rockchip_rgb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c
@@ -8,6 +8,7 @@
#include <linux/component.h>
#include <linux/media-bus-format.h>
#include <linux/of_graph.h>
+#include <linux/phy/phy.h>

#include <drm/display/drm_dp_helper.h>
#include <drm/drm_atomic_helper.h>
@@ -30,6 +31,7 @@ struct rockchip_rgb {
struct drm_bridge *bridge;
struct drm_encoder encoder;
struct drm_connector connector;
+ struct phy *dphy;
int output_mode;
};

@@ -168,6 +170,22 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
goto err_free_connector;
}

+ /* PHY */
+ rgb->dphy = devm_phy_get(dev, "dphy");
+ if (!IS_ERR(rgb->dphy)) {
+ ret = phy_init(rgb->dphy);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = phy_set_mode(rgb->dphy, PHY_MODE_TTL);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = phy_power_on(rgb->dphy);
+ if (ret)
+ return ERR_PTR(ret);
+ }
+
return rgb;

err_free_connector:
--
2.34.1

Subject: Re: [RFC PATCH 0/4] Add RGB ttl connection on rockchip phy

Hi all

On Sun, Oct 2, 2022 at 8:45 AM Michael Trimarchi
<[email protected]> wrote:
>
> The rockchip phy can be convigured in ttl mode. The phy is shared
> between lvds, dsi, ttl. The configuration that now I'm able to support
> has the display output on some set of pins on standard vop output
> and a set of pins using the ttl phy. The solution is not clean as I
> would like to have because some register that are used to enable
> the TTL, are in the same register area of the dsi controller.
> In order to test I must add the following
>
> dsi_dphy: phy@ff2e0000 {
>
> reg = <0x0 0xff2e0000 0x0 0x10000>,
> <0x0 0xff450000 0x0 0x10000>;
> ...
> }
>
> The problem here is the second region I have added is the same of
> dsi logic. Only one register is needed by the the phy driver
>

Is there anyone who has time to review it?

Michael

> Michael Trimarchi (4):
> phy: add PHY_MODE_TTL
> phy: rockchip: Add inno_is_valid_phy_mode
> phy: rockchip: Implement TTY phy mode
> drm/rockchip: rgb: Add dphy connection to rgb output
>
> drivers/gpu/drm/rockchip/rockchip_rgb.c | 18 +++++
> .../phy/rockchip/phy-rockchip-inno-dsidphy.c | 72 +++++++++++++++++++
> include/linux/phy/phy.h | 3 +-
> 3 files changed, 92 insertions(+), 1 deletion(-)
>
> --
> 2.34.1
>


--
Michael Nazzareno Trimarchi
Co-Founder & Chief Executive Officer
M. +39 347 913 2170
[email protected]
__________________________________

Amarula Solutions BV
Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
T. +31 (0)85 111 9172
[email protected]
http://www.amarulasolutions.com

2023-01-13 18:44:19

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 2/4] phy: rockchip: Add inno_is_valid_phy_mode

On 02-10-22, 08:45, Michael Trimarchi wrote:
> The function is used to avoid to enable clock on the hardware
> if the mode requested is invalid
>
> Signed-off-by: Michael Trimarchi <[email protected]>
> ---
> .../phy/rockchip/phy-rockchip-inno-dsidphy.c | 19 +++++++++++++++++++
> 1 file changed, 19 insertions(+)
>
> diff --git a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
> index 630e01b5c19b..644cf73cfd53 100644
> --- a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
> +++ b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
> @@ -217,6 +217,20 @@ static void phy_update_bits(struct inno_dsidphy *inno,
> writel(tmp, inno->phy_base + reg);
> }
>
> +static int inno_is_valid_phy_mode(struct inno_dsidphy *inno)
> +{
> + switch (inno->mode) {
> + case PHY_MODE_MIPI_DPHY:
> + break;
> + case PHY_MODE_LVDS:
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +};
> +
> static unsigned long inno_dsidphy_pll_calc_rate(struct inno_dsidphy *inno,
> unsigned long rate)
> {
> @@ -495,6 +509,11 @@ static void inno_dsidphy_lvds_mode_enable(struct inno_dsidphy *inno)
> static int inno_dsidphy_power_on(struct phy *phy)
> {
> struct inno_dsidphy *inno = phy_get_drvdata(phy);
> + int ret = 0;

this initialization is superfluous

> +
> + ret = inno_is_valid_phy_mode(inno);
> + if (ret)
> + return ret;
>
> clk_prepare_enable(inno->pclk_phy);
> clk_prepare_enable(inno->ref_clk);
> --
> 2.34.1

--
~Vinod