2018-05-19 18:33:11

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH 00/15] Add support for R40 HDMI pipeline

This series adds support for R40 HDMI pipeline. It is a bit special
than other already supported pipelines because it has additional unit
called TCON TOP responsible for relationship configuration between
mixers, TCONs and HDMI. Additionally, it has additional gates for DSI
and TV TCONs, TV encoder clock settings and pin muxing between LCD
and TV encoders.

However, it seems that TCON TOP will become a norm, since newer
Allwinner SoCs like H6 also have this unit.

I tested different possible configurations:
- mixer0 <> TCON-TV0 <> HDMI
- mixer0 <> TCON-TV1 <> HDMI
- mixer1 <> TCON-TV0 <> HDMI
- mixer1 <> TCON-TV1 <> HDMI

Please review.

Best regards,
Jernej

Jernej Skrabec (15):
clk: sunxi-ng: r40: Add minimal rate for video PLLs
clk: sunxi-ng: r40: Allow setting parent rate to display related
clocks
clk: sunxi-ng: r40: Export video PLLs
dt-bindings: display: sunxi-drm: Add TCON TOP description
drm/sun4i: Add TCON TOP driver
drm/sun4i: tcon: Add support for tcon-top
dt-bindings: display: sun4i-drm: Add R40 HDMI pipeline
drm/sun4i: DE2 mixer: Add index quirk
drm/sun4i: Add support for R40 mixers
drm/sun4i: Add support for R40 TV TCONs
drm/sun4i: DW HDMI PHY: Add support for second PLL
drm/sun4i: Add support for second clock parent to DW HDMI PHY clk
driver
drm/sun4i: Add support for A64 HDMI PHY
ARM: dts: sun8i: r40: Add HDMI pipeline
ARM: dts: sun8i: r40: Enable HDMI output on BananaPi M2 Ultra

.../bindings/display/sunxi/sun4i-drm.txt | 36 ++-
.../boot/dts/sun8i-r40-bananapi-m2-ultra.dts | 50 ++++
arch/arm/boot/dts/sun8i-r40.dtsi | 166 ++++++++++++
drivers/clk/sunxi-ng/ccu-sun8i-r40.c | 58 ++--
drivers/clk/sunxi-ng/ccu-sun8i-r40.h | 8 +-
drivers/gpu/drm/sun4i/Makefile | 3 +-
drivers/gpu/drm/sun4i/sun4i_tcon.c | 67 +++++
drivers/gpu/drm/sun4i/sun4i_tcon.h | 8 +
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 8 +-
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 61 ++++-
drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c | 90 ++++--
drivers/gpu/drm/sun4i/sun8i_mixer.c | 30 +-
drivers/gpu/drm/sun4i/sun8i_mixer.h | 2 +
drivers/gpu/drm/sun4i/sun8i_tcon_top.c | 256 ++++++++++++++++++
drivers/gpu/drm/sun4i/sun8i_tcon_top.h | 20 ++
include/dt-bindings/clock/sun8i-r40-ccu.h | 4 +
include/dt-bindings/clock/sun8i-tcon-top.h | 11 +
17 files changed, 813 insertions(+), 65 deletions(-)
create mode 100644 drivers/gpu/drm/sun4i/sun8i_tcon_top.c
create mode 100644 drivers/gpu/drm/sun4i/sun8i_tcon_top.h
create mode 100644 include/dt-bindings/clock/sun8i-tcon-top.h

--
2.17.0



2018-05-19 18:33:41

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH 09/15] drm/sun4i: Add support for R40 mixers

Both mixers have similar capabilities as others SoCs with DE2.

First mixer has 1 VI and 3 UI planes and supports HW scaling on all
planes.

Second mixer has 1 VI and 1 UI planes and also supports HW scaling on
all planes.

Signed-off-by: Jernej Skrabec <[email protected]>
---
drivers/gpu/drm/sun4i/sun8i_mixer.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 36d90c76317a..78aa878e305c 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -500,6 +500,24 @@ static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
.vi_num = 1,
};

+static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = {
+ .ccsc = 0,
+ .index = 0,
+ .mod_rate = 297000000,
+ .scaler_mask = 0xf,
+ .ui_num = 3,
+ .vi_num = 1,
+};
+
+static const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = {
+ .ccsc = 1,
+ .index = 1,
+ .mod_rate = 297000000,
+ .scaler_mask = 0x3,
+ .ui_num = 1,
+ .vi_num = 1,
+};
+
static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
.vi_num = 2,
.ui_num = 1,
@@ -521,6 +539,14 @@ static const struct of_device_id sun8i_mixer_of_table[] = {
.compatible = "allwinner,sun8i-h3-de2-mixer-0",
.data = &sun8i_h3_mixer0_cfg,
},
+ {
+ .compatible = "allwinner,sun8i-r40-de2-mixer-0",
+ .data = &sun8i_r40_mixer0_cfg,
+ },
+ {
+ .compatible = "allwinner,sun8i-r40-de2-mixer-1",
+ .data = &sun8i_r40_mixer1_cfg,
+ },
{
.compatible = "allwinner,sun8i-v3s-de2-mixer",
.data = &sun8i_v3s_mixer_cfg,
--
2.17.0


2018-05-19 18:33:56

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH 13/15] drm/sun4i: Add support for A64 HDMI PHY

PHY is the same as in H3, except it can switch between two clock
parents.

Signed-off-by: Jernej Skrabec <[email protected]>
---
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 12 ++++++++++++
1 file changed, 12 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
index 7a911f0a3ae3..0c9d67bb1007 100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -396,6 +396,14 @@ static struct regmap_config sun8i_hdmi_phy_regmap_config = {
.name = "phy"
};

+static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = {
+ .has_phy_clk = true,
+ .has_second_pll = true,
+ .phy_init = &sun8i_hdmi_phy_init_h3,
+ .phy_disable = &sun8i_hdmi_phy_disable_h3,
+ .phy_config = &sun8i_hdmi_phy_config_h3,
+};
+
static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = {
.phy_init = &sun8i_hdmi_phy_init_a83t,
.phy_disable = &sun8i_hdmi_phy_disable_a83t,
@@ -410,6 +418,10 @@ static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = {
};

static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
+ {
+ .compatible = "allwinner,sun50i-a64-hdmi-phy",
+ .data = &sun50i_a64_hdmi_phy,
+ },
{
.compatible = "allwinner,sun8i-a83t-hdmi-phy",
.data = &sun8i_a83t_hdmi_phy,
--
2.17.0


2018-05-19 18:34:13

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH 10/15] drm/sun4i: Add support for R40 TV TCONs

R40 display pipeline has a lot of possible configurations. HDMI can be
connected to 2 different TCONs (out of 4) and mixers can be connected to
any TCON. All this must be configured in TCON TOP.

Along with definition of TCON capabilities also add mux callback, which
can configure this complex pipeline.

For now, only TCON TV is supported.

Signed-off-by: Jernej Skrabec <[email protected]>
---
drivers/gpu/drm/sun4i/sun4i_tcon.c | 39 ++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index e0c562ce1c22..81b9551e4f78 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -1274,6 +1274,31 @@ static int sun6i_tcon_set_mux(struct sun4i_tcon *tcon,
return 0;
}

+static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon,
+ const struct drm_encoder *encoder,
+ int index)
+{
+ if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
+ sun8i_tcon_top_set_hdmi_src(tcon->tcon_top, index);
+
+ sun8i_tcon_top_de_config(tcon->tcon_top, tcon->id,
+ tcon_type_tv, index);
+
+ return 0;
+}
+
+static int sun8i_r40_tcon_tv_set_mux_0(struct sun4i_tcon *tcon,
+ const struct drm_encoder *encoder)
+{
+ return sun8i_r40_tcon_tv_set_mux(tcon, encoder, 0);
+}
+
+static int sun8i_r40_tcon_tv_set_mux_1(struct sun4i_tcon *tcon,
+ const struct drm_encoder *encoder)
+{
+ return sun8i_r40_tcon_tv_set_mux(tcon, encoder, 1);
+}
+
static const struct sun4i_tcon_quirks sun4i_a10_quirks = {
.has_channel_0 = true,
.has_channel_1 = true,
@@ -1321,6 +1346,18 @@ static const struct sun4i_tcon_quirks sun8i_a83t_tv_quirks = {
.has_channel_1 = true,
};

+static const struct sun4i_tcon_quirks sun8i_r40_tv_0_quirks = {
+ .has_channel_1 = true,
+ .needs_tcon_top = true,
+ .set_mux = sun8i_r40_tcon_tv_set_mux_0,
+};
+
+static const struct sun4i_tcon_quirks sun8i_r40_tv_1_quirks = {
+ .has_channel_1 = true,
+ .needs_tcon_top = true,
+ .set_mux = sun8i_r40_tcon_tv_set_mux_1,
+};
+
static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
.has_channel_0 = true,
};
@@ -1345,6 +1382,8 @@ const struct of_device_id sun4i_tcon_of_table[] = {
{ .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },
{ .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks },
{ .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks },
+ { .compatible = "allwinner,sun8i-r40-tcon-tv-0", .data = &sun8i_r40_tv_0_quirks },
+ { .compatible = "allwinner,sun8i-r40-tcon-tv-1", .data = &sun8i_r40_tv_1_quirks },
{ .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },
{ .compatible = "allwinner,sun9i-a80-tcon-lcd", .data = &sun9i_a80_tcon_lcd_quirks },
{ .compatible = "allwinner,sun9i-a80-tcon-tv", .data = &sun9i_a80_tcon_tv_quirks },
--
2.17.0


2018-05-19 18:34:27

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH 14/15] ARM: dts: sun8i: r40: Add HDMI pipeline

Add all entries needed for HDMI to function properly.

Since R40 has highly configurable pipeline, both mixers and both TCON
TVs are added. Board specific DT should then connect them together to
best fit the purpose of the board.

Signed-off-by: Jernej Skrabec <[email protected]>
---
arch/arm/boot/dts/sun8i-r40.dtsi | 166 +++++++++++++++++++++++++++++++
1 file changed, 166 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-r40.dtsi b/arch/arm/boot/dts/sun8i-r40.dtsi
index 173dcc1652d2..6d5407964997 100644
--- a/arch/arm/boot/dts/sun8i-r40.dtsi
+++ b/arch/arm/boot/dts/sun8i-r40.dtsi
@@ -42,8 +42,11 @@
*/

#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/sun8i-de2.h>
#include <dt-bindings/clock/sun8i-r40-ccu.h>
+#include <dt-bindings/clock/sun8i-tcon-top.h>
#include <dt-bindings/reset/sun8i-r40-ccu.h>
+#include <dt-bindings/reset/sun8i-de2.h>

/ {
#address-cells = <1>;
@@ -99,12 +102,70 @@
};
};

+ de: display-engine {
+ compatible = "allwinner,sun8i-r40-display-engine",
+ "allwinner,sun8i-h3-display-engine";
+ allwinner,pipelines = <&mixer0>, <&mixer1>;
+ status = "disabled";
+ };
+
soc {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;

+ display_clocks: clock@1000000 {
+ compatible = "allwinner,sun8i-r40-de2-clk",
+ "allwinner,sun8i-h3-de2-clk";
+ reg = <0x01000000 0x100000>;
+ clocks = <&ccu CLK_DE>,
+ <&ccu CLK_BUS_DE>;
+ clock-names = "mod",
+ "bus";
+ resets = <&ccu RST_BUS_DE>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ mixer0: mixer@1100000 {
+ compatible = "allwinner,sun8i-r40-de2-mixer-0";
+ reg = <0x01100000 0x100000>;
+ clocks = <&display_clocks CLK_BUS_MIXER0>,
+ <&display_clocks CLK_MIXER0>;
+ clock-names = "bus",
+ "mod";
+ resets = <&display_clocks RST_MIXER0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mixer0_out: port@1 {
+ reg = <1>;
+ };
+ };
+ };
+
+ mixer1: mixer@1200000 {
+ compatible = "allwinner,sun8i-r40-de2-mixer-1";
+ reg = <0x01200000 0x100000>;
+ clocks = <&display_clocks CLK_BUS_MIXER1>,
+ <&display_clocks CLK_MIXER1>;
+ clock-names = "bus",
+ "mod";
+ resets = <&display_clocks RST_WB>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mixer1_out: port@1 {
+ reg = <1>;
+ };
+ };
+ };
+
nmi_intc: interrupt-controller@1c00030 {
compatible = "allwinner,sun7i-a20-sc-nmi";
interrupt-controller;
@@ -451,6 +512,70 @@
#size-cells = <0>;
};

+ tcon_top: tcon-top@1c70000 {
+ compatible = "allwinner,sun8i-r40-tcon-top";
+ reg = <0x01c70000 0x1000>;
+ clocks = <&ccu CLK_BUS_TCON_TOP>;
+ clock-names = "bus";
+ resets = <&ccu RST_BUS_TCON_TOP>;
+ reset-names = "rst";
+ #clock-cells = <1>;
+ };
+
+ tcon_tv0: lcd-controller@1c73000 {
+ compatible = "allwinner,sun8i-r40-tcon-tv-0";
+ reg = <0x01c73000 0x1000>;
+ interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_TCON_TV0>, <&ccu CLK_TCON_TV0>,
+ <&tcon_top 1>;
+ clock-names = "ahb", "tcon-ch1", "tcon-top";
+ resets = <&ccu RST_BUS_TCON_TV0>;
+ reset-names = "lcd";
+ allwinner,tcon-top = <&tcon_top>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tcon_tv0_in: port@0 {
+ reg = <0>;
+ };
+
+ tcon_tv0_out: port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ };
+ };
+ };
+
+ tcon_tv1: lcd-controller@1c74000 {
+ compatible = "allwinner,sun8i-r40-tcon-tv-1";
+ reg = <0x01c74000 0x1000>;
+ interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_TCON_TV1>, <&ccu CLK_TCON_TV1>,
+ <&tcon_top 2>;
+ clock-names = "ahb", "tcon-ch1", "tcon-top";
+ resets = <&ccu RST_BUS_TCON_TV1>;
+ reset-names = "lcd";
+ allwinner,tcon-top = <&tcon_top>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tcon_tv1_in: port@0 {
+ reg = <0>;
+ };
+
+ tcon_tv1_out: port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ };
+ };
+ };
+
gic: interrupt-controller@1c81000 {
compatible = "arm,gic-400";
reg = <0x01c81000 0x1000>,
@@ -461,6 +586,47 @@
#interrupt-cells = <3>;
interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
};
+
+ hdmi: hdmi@1ee0000 {
+ compatible = "allwinner,sun8i-r40-dw-hdmi",
+ "allwinner,sun8i-a83t-dw-hdmi";
+ reg = <0x01ee0000 0x10000>;
+ reg-io-width = <1>;
+ interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_HDMI0>, <&ccu CLK_HDMI_SLOW>,
+ <&ccu CLK_HDMI>;
+ clock-names = "iahb", "isfr", "tmds";
+ resets = <&ccu RST_BUS_HDMI1>;
+ reset-names = "ctrl";
+ phys = <&hdmi_phy>;
+ phy-names = "hdmi-phy";
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ hdmi_in: port@0 {
+ reg = <0>;
+ };
+
+ hdmi_out: port@1 {
+ reg = <1>;
+ };
+ };
+ };
+
+ hdmi_phy: hdmi-phy@1ef0000 {
+ compatible = "allwinner,sun8i-r40-hdmi-phy",
+ "allwinner,sun50i-a64-hdmi-phy";
+ reg = <0x01ef0000 0x10000>;
+ clocks = <&ccu CLK_BUS_HDMI1>, <&ccu CLK_HDMI_SLOW>,
+ <&ccu 7>, <&ccu 16>;
+ clock-names = "bus", "mod", "pll-0", "pll-1";
+ resets = <&ccu RST_BUS_HDMI0>;
+ reset-names = "phy";
+ #phy-cells = <0>;
+ };
};

timer {
--
2.17.0


2018-05-19 18:34:44

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH 15/15] ARM: dts: sun8i: r40: Enable HDMI output on BananaPi M2 Ultra

Since HDMI can be considered as main output, most capable mixer is
connected to it (mixer0).

Signed-off-by: Jernej Skrabec <[email protected]>
---
.../boot/dts/sun8i-r40-bananapi-m2-ultra.dts | 50 +++++++++++++++++++
1 file changed, 50 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts b/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
index 27d9ccd0ef2f..66b492ad5847 100644
--- a/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
+++ b/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
@@ -58,6 +58,17 @@
stdout-path = "serial0:115200n8";
};

+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
leds {
compatible = "gpio-leds";

@@ -93,6 +104,10 @@
};
};

+&de {
+ status = "okay";
+};
+
&ehci1 {
status = "okay";
};
@@ -101,6 +116,22 @@
status = "okay";
};

+&hdmi {
+ status = "okay";
+};
+
+&hdmi_in {
+ hdmi_in_tcon_tv0: endpoint {
+ remote-endpoint = <&tcon_tv0_out_hdmi>;
+ };
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
&i2c0 {
status = "okay";

@@ -161,6 +192,12 @@
regulator-name = "vcc-wifi";
};

+&mixer0_out {
+ mixer0_out_tcon_tv0: endpoint {
+ remote-endpoint = <&tcon_tv0_in_mixer0>;
+ };
+};
+
&mmc0 {
vmmc-supply = <&reg_dcdc1>;
bus-width = <4>;
@@ -195,6 +232,19 @@
status = "okay";
};

+&tcon_tv0_in {
+ tcon_tv0_in_mixer0: endpoint {
+ remote-endpoint = <&mixer0_out_tcon_tv0>;
+ };
+};
+
+&tcon_tv0_out {
+ tcon_tv0_out_hdmi: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&hdmi_in_tcon_tv0>;
+ };
+};
+
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pb_pins>;
--
2.17.0


2018-05-19 18:34:53

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH 12/15] drm/sun4i: Add support for second clock parent to DW HDMI PHY clk driver

Expand HDMI PHY clock driver to support second clock parent.

Signed-off-by: Jernej Skrabec <[email protected]>
---
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 6 +-
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 29 ++++++-
drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c | 90 ++++++++++++++++------
3 files changed, 98 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
index 801a17222762..aadbe0a10b0c 100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
@@ -98,7 +98,8 @@
#define SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN BIT(29)
#define SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN BIT(28)
#define SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 BIT(27)
-#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL BIT(26)
+#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK BIT(26)
+#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT 26
#define SUN8I_HDMI_PHY_PLL_CFG1_PLLEN BIT(25)
#define SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(x) ((x) << 22)
#define SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(x) ((x) << 20)
@@ -190,6 +191,7 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi);
void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void);

-int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev);
+int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev,
+ bool second_parent);

#endif /* _SUN8I_DW_HDMI_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
index deba47ed69d8..7a911f0a3ae3 100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -183,7 +183,13 @@ static int sun8i_hdmi_phy_config_h3(struct dw_hdmi *hdmi,
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK, 0);

- regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, pll_cfg1_init);
+ /*
+ * NOTE: We have to be careful not to overwrite PHY parent
+ * clock selection bit and clock divider.
+ */
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
+ ~SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK,
+ pll_cfg1_init);
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG,
(u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK,
pll_cfg2_init);
@@ -352,6 +358,10 @@ static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
SUN8I_HDMI_PHY_ANA_CFG3_SDAEN);

+ /* reset PLL clock configuration */
+ regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 0);
+ regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG, 0);
+
/* set HW control of CEC pins */
regmap_write(phy->regs, SUN8I_HDMI_PHY_CEC_REG, 0);

@@ -481,18 +491,28 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
}
}

- ret = sun8i_phy_clk_create(phy, dev);
+ ret = sun8i_phy_clk_create(phy, dev,
+ phy->variant->has_second_pll);
if (ret) {
dev_err(dev, "Couldn't create the PHY clock\n");
goto err_put_clk_pll1;
}
+
+ /*
+ * Even though HDMI PHY clock doesn't have enable/disable
+ * handlers, we have to enable it. Otherwise it could happen
+ * that parent PLL is not enabled by clock framework in a
+ * highly unlikely event when parent PLL is used solely for
+ * HDMI PHY clock.
+ */
+ clk_prepare_enable(phy->clk_phy);
}

phy->rst_phy = of_reset_control_get_shared(node, "phy");
if (IS_ERR(phy->rst_phy)) {
dev_err(dev, "Could not get phy reset control\n");
ret = PTR_ERR(phy->rst_phy);
- goto err_put_clk_pll1;
+ goto err_disable_clk_phy;
}

ret = reset_control_deassert(phy->rst_phy);
@@ -523,6 +543,8 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
reset_control_assert(phy->rst_phy);
err_put_rst_phy:
reset_control_put(phy->rst_phy);
+err_disable_clk_phy:
+ clk_disable_unprepare(phy->clk_phy);
err_put_clk_pll1:
clk_put(phy->clk_pll1);
err_put_clk_pll0:
@@ -541,6 +563,7 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi)

clk_disable_unprepare(phy->clk_mod);
clk_disable_unprepare(phy->clk_bus);
+ clk_disable_unprepare(phy->clk_phy);

reset_control_assert(phy->rst_phy);

diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c
index faea449812f8..a4d31fe3abff 100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c
@@ -22,35 +22,45 @@ static int sun8i_phy_clk_determine_rate(struct clk_hw *hw,
{
unsigned long rate = req->rate;
unsigned long best_rate = 0;
+ struct clk_hw *best_parent = NULL;
struct clk_hw *parent;
int best_div = 1;
- int i;
+ int i, p;

- parent = clk_hw_get_parent(hw);
-
- for (i = 1; i <= 16; i++) {
- unsigned long ideal = rate * i;
- unsigned long rounded;
-
- rounded = clk_hw_round_rate(parent, ideal);
+ for (p = 0; p < clk_hw_get_num_parents(hw); p++) {
+ parent = clk_hw_get_parent_by_index(hw, p);
+ if (!parent)
+ continue;

- if (rounded == ideal) {
- best_rate = rounded;
- best_div = i;
- break;
+ for (i = 1; i <= 16; i++) {
+ unsigned long ideal = rate * i;
+ unsigned long rounded;
+
+ rounded = clk_hw_round_rate(parent, ideal);
+
+ if (rounded == ideal) {
+ best_rate = rounded;
+ best_div = i;
+ best_parent = parent;
+ break;
+ }
+
+ if (!best_rate ||
+ abs(rate - rounded / i) <
+ abs(rate - best_rate / best_div)) {
+ best_rate = rounded;
+ best_div = i;
+ best_parent = parent;
+ }
}

- if (!best_rate ||
- abs(rate - rounded / i) <
- abs(rate - best_rate / best_div)) {
- best_rate = rounded;
- best_div = i;
- }
+ if (best_rate / best_div == rate)
+ break;
}

req->rate = best_rate / best_div;
req->best_parent_rate = best_rate;
- req->best_parent_hw = parent;
+ req->best_parent_hw = best_parent;

return 0;
}
@@ -95,22 +105,58 @@ static int sun8i_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
return 0;
}

+static u8 sun8i_phy_clk_get_parent(struct clk_hw *hw)
+{
+ struct sun8i_phy_clk *priv = hw_to_phy_clk(hw);
+ u32 reg;
+
+ regmap_read(priv->phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, &reg);
+ reg = (reg & SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK) >>
+ SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT;
+
+ return reg;
+}
+
+static int sun8i_phy_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct sun8i_phy_clk *priv = hw_to_phy_clk(hw);
+
+ if (index > 1)
+ return -EINVAL;
+
+ regmap_update_bits(priv->phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
+ SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK,
+ index << SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT);
+
+ return 0;
+}
+
static const struct clk_ops sun8i_phy_clk_ops = {
.determine_rate = sun8i_phy_clk_determine_rate,
.recalc_rate = sun8i_phy_clk_recalc_rate,
.set_rate = sun8i_phy_clk_set_rate,
+
+ .get_parent = sun8i_phy_clk_get_parent,
+ .set_parent = sun8i_phy_clk_set_parent,
};

-int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev)
+int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev,
+ bool second_parent)
{
struct clk_init_data init;
struct sun8i_phy_clk *priv;
- const char *parents[1];
+ const char *parents[2];

parents[0] = __clk_get_name(phy->clk_pll0);
if (!parents[0])
return -ENODEV;

+ if (second_parent) {
+ parents[1] = __clk_get_name(phy->clk_pll1);
+ if (!parents[1])
+ return -ENODEV;
+ }
+
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -118,7 +164,7 @@ int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev)
init.name = "hdmi-phy-clk";
init.ops = &sun8i_phy_clk_ops;
init.parent_names = parents;
- init.num_parents = 1;
+ init.num_parents = second_parent ? 2 : 1;
init.flags = CLK_SET_RATE_PARENT;

priv->phy = phy;
--
2.17.0


2018-05-19 18:35:11

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH 08/15] drm/sun4i: DE2 mixer: Add index quirk

When TCON sets up TCON TOP, it needs to know mixer index. Here we do that
by setting engine ID to number provided in mixer index quirk.

Signed-off-by: Jernej Skrabec <[email protected]>
---
drivers/gpu/drm/sun4i/sun8i_mixer.c | 4 ++--
drivers/gpu/drm/sun4i/sun8i_mixer.h | 2 ++
2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 126899d6f0d3..36d90c76317a 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -353,13 +353,13 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
dev_set_drvdata(dev, mixer);
mixer->engine.ops = &sun8i_engine_ops;
mixer->engine.node = dev->of_node;
- /* The ID of the mixer currently doesn't matter */
- mixer->engine.id = -1;

mixer->cfg = of_device_get_match_data(dev);
if (!mixer->cfg)
return -EINVAL;

+ mixer->engine.id = mixer->cfg->index;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(dev, res);
if (IS_ERR(regs))
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index f34e70c42adf..aeda6e9a7627 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -123,6 +123,7 @@ struct de2_fmt_info {
* are invalid.
* @mod_rate: module clock rate that needs to be set in order to have
* a functional block.
+ * @index: mixer index, needed to properly set TCON TOP
*/
struct sun8i_mixer_cfg {
int vi_num;
@@ -130,6 +131,7 @@ struct sun8i_mixer_cfg {
int scaler_mask;
int ccsc;
unsigned long mod_rate;
+ int index;
};

struct sun8i_mixer {
--
2.17.0


2018-05-19 18:35:20

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH 11/15] drm/sun4i: DW HDMI PHY: Add support for second PLL

Some DW HDMI PHYs like those found in A64 and R40 SoCs, can select
between two clock parents.

Add code which reads second PLL from DT.

Signed-off-by: Jernej Skrabec <[email protected]>
---
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 2 ++
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 22 ++++++++++++++++------
2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
index 79154f0f674a..801a17222762 100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
@@ -147,6 +147,7 @@ struct sun8i_hdmi_phy;

struct sun8i_hdmi_phy_variant {
bool has_phy_clk;
+ bool has_second_pll;
void (*phy_init)(struct sun8i_hdmi_phy *phy);
void (*phy_disable)(struct dw_hdmi *hdmi,
struct sun8i_hdmi_phy *phy);
@@ -160,6 +161,7 @@ struct sun8i_hdmi_phy {
struct clk *clk_mod;
struct clk *clk_phy;
struct clk *clk_pll0;
+ struct clk *clk_pll1;
unsigned int rcal;
struct regmap *regs;
struct reset_control *rst_phy;
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
index 5a52fc489a9d..deba47ed69d8 100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -472,10 +472,19 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
goto err_put_clk_mod;
}

+ if (phy->variant->has_second_pll) {
+ phy->clk_pll1 = of_clk_get_by_name(node, "pll-1");
+ if (IS_ERR(phy->clk_pll1)) {
+ dev_err(dev, "Could not get pll-1 clock\n");
+ ret = PTR_ERR(phy->clk_pll1);
+ goto err_put_clk_pll0;
+ }
+ }
+
ret = sun8i_phy_clk_create(phy, dev);
if (ret) {
dev_err(dev, "Couldn't create the PHY clock\n");
- goto err_put_clk_pll0;
+ goto err_put_clk_pll1;
}
}

@@ -483,7 +492,7 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
if (IS_ERR(phy->rst_phy)) {
dev_err(dev, "Could not get phy reset control\n");
ret = PTR_ERR(phy->rst_phy);
- goto err_put_clk_pll0;
+ goto err_put_clk_pll1;
}

ret = reset_control_deassert(phy->rst_phy);
@@ -514,9 +523,10 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
reset_control_assert(phy->rst_phy);
err_put_rst_phy:
reset_control_put(phy->rst_phy);
+err_put_clk_pll1:
+ clk_put(phy->clk_pll1);
err_put_clk_pll0:
- if (phy->variant->has_phy_clk)
- clk_put(phy->clk_pll0);
+ clk_put(phy->clk_pll0);
err_put_clk_mod:
clk_put(phy->clk_mod);
err_put_clk_bus:
@@ -536,8 +546,8 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi)

reset_control_put(phy->rst_phy);

- if (phy->variant->has_phy_clk)
- clk_put(phy->clk_pll0);
+ clk_put(phy->clk_pll0);
+ clk_put(phy->clk_pll1);
clk_put(phy->clk_mod);
clk_put(phy->clk_bus);
}
--
2.17.0


2018-05-19 18:36:12

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH 01/15] clk: sunxi-ng: r40: Add minimal rate for video PLLs

According to documentation and experience with other similar SoCs, video
PLLs don't work stable if their output frequency is set below 192 MHz.

Because of that, set minimal rate to both R40 video PLLs to 192 MHz.

Signed-off-by: Jernej Skrabec <[email protected]>
---
drivers/clk/sunxi-ng/ccu-sun8i-r40.c | 46 +++++++++++++++-------------
1 file changed, 24 insertions(+), 22 deletions(-)

diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
index 933f2e68f42a..c16a62a7bdbd 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
@@ -65,17 +65,18 @@ static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base",
CLK_SET_RATE_UNGATE);

/* TODO: The result of N/M is required to be in [8, 25] range. */
-static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video0_clk, "pll-video0",
- "osc24M", 0x0010,
- 8, 7, /* N */
- 0, 4, /* M */
- BIT(24), /* frac enable */
- BIT(25), /* frac select */
- 270000000, /* frac rate 0 */
- 297000000, /* frac rate 1 */
- BIT(31), /* gate */
- BIT(28), /* lock */
- CLK_SET_RATE_UNGATE);
+static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(pll_video0_clk, "pll-video0",
+ "osc24M", 0x0010,
+ 192000000, /* Minimum rate */
+ 8, 7, /* N */
+ 0, 4, /* M */
+ BIT(24), /* frac enable */
+ BIT(25), /* frac select */
+ 270000000, /* frac rate 0 */
+ 297000000, /* frac rate 1 */
+ BIT(31), /* gate */
+ BIT(28), /* lock */
+ CLK_SET_RATE_UNGATE);

/* TODO: The result of N/M is required to be in [8, 25] range. */
static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve",
@@ -151,17 +152,18 @@ static struct ccu_nk pll_periph1_clk = {
};

/* TODO: The result of N/M is required to be in [8, 25] range. */
-static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video1_clk, "pll-video1",
- "osc24M", 0x030,
- 8, 7, /* N */
- 0, 4, /* M */
- BIT(24), /* frac enable */
- BIT(25), /* frac select */
- 270000000, /* frac rate 0 */
- 297000000, /* frac rate 1 */
- BIT(31), /* gate */
- BIT(28), /* lock */
- CLK_SET_RATE_UNGATE);
+static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(pll_video1_clk, "pll-video1",
+ "osc24M", 0x030,
+ 192000000, /* Minimum rate */
+ 8, 7, /* N */
+ 0, 4, /* M */
+ BIT(24), /* frac enable */
+ BIT(25), /* frac select */
+ 270000000, /* frac rate 0 */
+ 297000000, /* frac rate 1 */
+ BIT(31), /* gate */
+ BIT(28), /* lock */
+ CLK_SET_RATE_UNGATE);

static struct ccu_nkm pll_sata_clk = {
.enable = BIT(31),
--
2.17.0


2018-05-19 18:36:19

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH 02/15] clk: sunxi-ng: r40: Allow setting parent rate to display related clocks

Display related peripherals need precise clocks to operate correctly.

Allow DE2, TCONs and HDMI to set parent clock.

Signed-off-by: Jernej Skrabec <[email protected]>
---
drivers/clk/sunxi-ng/ccu-sun8i-r40.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
index c16a62a7bdbd..fa5317719684 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
@@ -655,7 +655,8 @@ static SUNXI_CCU_GATE(dram_deinterlace_clk, "dram-deinterlace", "dram",

static const char * const de_parents[] = { "pll-periph0-2x", "pll-de" };
static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de", de_parents,
- 0x104, 0, 4, 24, 3, BIT(31), 0);
+ 0x104, 0, 4, 24, 3, BIT(31),
+ CLK_SET_RATE_PARENT);
static SUNXI_CCU_M_WITH_MUX_GATE(mp_clk, "mp", de_parents,
0x108, 0, 4, 24, 3, BIT(31), 0);

@@ -667,9 +668,11 @@ static SUNXI_CCU_MUX_WITH_GATE(tcon_lcd0_clk, "tcon-lcd0", tcon_parents,
static SUNXI_CCU_MUX_WITH_GATE(tcon_lcd1_clk, "tcon-lcd1", tcon_parents,
0x114, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
static SUNXI_CCU_M_WITH_MUX_GATE(tcon_tv0_clk, "tcon-tv0", tcon_parents,
- 0x118, 0, 4, 24, 3, BIT(31), 0);
+ 0x118, 0, 4, 24, 3, BIT(31),
+ CLK_SET_RATE_PARENT);
static SUNXI_CCU_M_WITH_MUX_GATE(tcon_tv1_clk, "tcon-tv1", tcon_parents,
- 0x11c, 0, 4, 24, 3, BIT(31), 0);
+ 0x11c, 0, 4, 24, 3, BIT(31),
+ CLK_SET_RATE_PARENT);

static const char * const deinterlace_parents[] = { "pll-periph0",
"pll-periph1" };
@@ -699,7 +702,8 @@ static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M",

static const char * const hdmi_parents[] = { "pll-video0", "pll-video1" };
static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents,
- 0x150, 0, 4, 24, 2, BIT(31), 0);
+ 0x150, 0, 4, 24, 2, BIT(31),
+ CLK_SET_RATE_PARENT);

static SUNXI_CCU_GATE(hdmi_slow_clk, "hdmi-slow", "osc24M",
0x154, BIT(31), 0);
--
2.17.0


2018-05-19 18:36:38

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH 06/15] drm/sun4i: tcon: Add support for tcon-top

If SoC has TCON TOP unit, it has to be configured from TCON, since it
has all information needed. Additionally, if it is TCON TV, it must also
enable bus gate inside TCON TOP unit.

Add support for such TCONs.

Signed-off-by: Jernej Skrabec <[email protected]>
---
drivers/gpu/drm/sun4i/sun4i_tcon.c | 28 ++++++++++++++++++++++++++++
drivers/gpu/drm/sun4i/sun4i_tcon.h | 8 ++++++++
2 files changed, 36 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index 08747fc3ee71..e0c562ce1c22 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -688,6 +688,16 @@ static int sun4i_tcon_init_clocks(struct device *dev,
dev_err(dev, "Couldn't get the TCON bus clock\n");
return PTR_ERR(tcon->clk);
}
+
+ if (tcon->quirks->needs_tcon_top && tcon->quirks->has_channel_1) {
+ tcon->top_clk = devm_clk_get(dev, "tcon-top");
+ if (IS_ERR(tcon->top_clk)) {
+ dev_err(dev, "Couldn't get the TCON TOP bus clock\n");
+ return PTR_ERR(tcon->top_clk);
+ }
+ clk_prepare_enable(tcon->top_clk);
+ }
+
clk_prepare_enable(tcon->clk);

if (tcon->quirks->has_channel_0) {
@@ -712,6 +722,7 @@ static int sun4i_tcon_init_clocks(struct device *dev,
static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
{
clk_disable_unprepare(tcon->clk);
+ clk_disable_unprepare(tcon->top_clk);
}

static int sun4i_tcon_init_irq(struct device *dev,
@@ -980,6 +991,23 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
tcon->id = engine->id;
tcon->quirks = of_device_get_match_data(dev);

+ if (tcon->quirks->needs_tcon_top) {
+ struct device_node *np;
+
+ np = of_parse_phandle(dev->of_node, "allwinner,tcon-top", 0);
+ if (np) {
+ struct platform_device *pdev;
+
+ pdev = of_find_device_by_node(np);
+ if (pdev)
+ tcon->tcon_top = platform_get_drvdata(pdev);
+ of_node_put(np);
+
+ if (!tcon->tcon_top)
+ return -EPROBE_DEFER;
+ }
+ }
+
tcon->lcd_rst = devm_reset_control_get(dev, "lcd");
if (IS_ERR(tcon->lcd_rst)) {
dev_err(dev, "Couldn't get our reset line\n");
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index f6a071cd5a6f..26be0d317a38 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -20,6 +20,8 @@
#include <linux/list.h>
#include <linux/reset.h>

+#include "sun8i_tcon_top.h"
+
#define SUN4I_TCON_GCTL_REG 0x0
#define SUN4I_TCON_GCTL_TCON_ENABLE BIT(31)
#define SUN4I_TCON_GCTL_IOMAP_MASK BIT(0)
@@ -224,6 +226,7 @@ struct sun4i_tcon_quirks {
bool needs_de_be_mux; /* sun6i needs mux to select backend */
bool needs_edp_reset; /* a80 edp reset needed for tcon0 access */
bool supports_lvds; /* Does the TCON support an LVDS output? */
+ bool needs_tcon_top; /* TCON TOP holds additional muxing configuration */

/* callback to handle tcon muxing options */
int (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *);
@@ -249,6 +252,9 @@ struct sun4i_tcon {
u8 dclk_max_div;
u8 dclk_min_div;

+ /* TCON TOP clock */
+ struct clk *top_clk;
+
/* Reset control */
struct reset_control *lcd_rst;
struct reset_control *lvds_rst;
@@ -263,6 +269,8 @@ struct sun4i_tcon {

int id;

+ struct sun8i_tcon_top *tcon_top;
+
/* TCON list management */
struct list_head list;
};
--
2.17.0


2018-05-19 18:36:41

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH 07/15] dt-bindings: display: sun4i-drm: Add R40 HDMI pipeline

Missing compatibles and descriptions needed to implement R40 HDMI
pipeline are added.

For mixers only compatibles are added.

TCON description is expanded with R40 TV TCON compatibles. If the SoC
has TCON TOP unit, phandle to that unit has to be specified. Additional
clock has to be specified if SoC has TCON TOP and TCON is TV TCON.

New compatible is added for DWC HDMI PHY, which has additional clock
specified.

Signed-off-by: Jernej Skrabec <[email protected]>
---
.../bindings/display/sunxi/sun4i-drm.txt | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
index a099957ab62a..634276f713e8 100644
--- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
+++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
@@ -101,6 +101,7 @@ DWC HDMI PHY

Required properties:
- compatible: value must be one of:
+ * allwinner,sun50i-a64-hdmi-phy
* allwinner,sun8i-a83t-hdmi-phy
* allwinner,sun8i-h3-hdmi-phy
- reg: base address and size of memory-mapped region
@@ -111,8 +112,9 @@ Required properties:
- resets: phandle to the reset controller driving the PHY
- reset-names: must be "phy"

-H3 HDMI PHY requires additional clock:
+H3 and A64 HDMI PHY requires additional clocks:
- pll-0: parent of phy clock
+ - pll-1: second possible phy clock parent (A64 only)

TV Encoder
----------
@@ -145,6 +147,8 @@ Required properties:
* allwinner,sun8i-a33-tcon
* allwinner,sun8i-a83t-tcon-lcd
* allwinner,sun8i-a83t-tcon-tv
+ * allwinner,sun8i-r40-tcon-tv-0
+ * allwinner,sun8i-r40-tcon-tv-1
* allwinner,sun8i-v3s-tcon
* allwinner,sun9i-a80-tcon-lcd
* allwinner,sun9i-a80-tcon-tv
@@ -179,7 +183,7 @@ For TCONs with channel 0, there is one more clock required:
For TCONs with channel 1, there is one more clock required:
- 'tcon-ch1': The clock driving the TCON channel 1

-When TCON support LVDS (all TCONs except TV TCON on A83T and those found
+When TCON support LVDS (all TCONs except TV TCONs on A83T, R40 and those found
in A13, H3, H5 and V3s SoCs), you need one more reset line:
- 'lvds': The reset line driving the LVDS logic

@@ -187,6 +191,12 @@ And on the A23, A31, A31s and A33, you need one more clock line:
- 'lvds-alt': An alternative clock source, separate from the TCON channel 0
clock, that can be used to drive the LVDS clock

+If SoC has TCON TOP, like R40, TCON has to have phandle to TCON TOP:
+ - 'allwinner,tcon-top': Phandle to TCON TOP unit
+
+TV TCONs which have phandle to TCON TOP need one more clock:
+ - 'tcon-top': TV TCON gate found in TCON TOP unit
+
TCON TOP
--------

@@ -330,6 +340,8 @@ Required properties:
* allwinner,sun8i-a83t-de2-mixer-0
* allwinner,sun8i-a83t-de2-mixer-1
* allwinner,sun8i-h3-de2-mixer-0
+ * allwinner,sun8i-r40-de2-mixer-0
+ * allwinner,sun8i-r40-de2-mixer-1
* allwinner,sun8i-v3s-de2-mixer
- reg: base address and size of the memory-mapped region.
- clocks: phandles to the clocks feeding the mixer
--
2.17.0


2018-05-19 18:36:59

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH 05/15] drm/sun4i: Add TCON TOP driver

As already described in DT binding, TCON TOP is responsible for
configuring display pipeline. In this initial driver focus is on HDMI
pipeline, so TVE and LCD configuration is not implemented.

Implemented features:
- HDMI source selection
- clock driver (TCON and DSI gating)
- connecting mixers and TCONS

Something similar also existed in previous SoCs, except that it was part
of first TCON.

Signed-off-by: Jernej Skrabec <[email protected]>
---
drivers/gpu/drm/sun4i/Makefile | 3 +-
drivers/gpu/drm/sun4i/sun8i_tcon_top.c | 256 +++++++++++++++++++++
drivers/gpu/drm/sun4i/sun8i_tcon_top.h | 20 ++
include/dt-bindings/clock/sun8i-tcon-top.h | 11 +
4 files changed, 289 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/sun4i/sun8i_tcon_top.c
create mode 100644 drivers/gpu/drm/sun4i/sun8i_tcon_top.h
create mode 100644 include/dt-bindings/clock/sun8i-tcon-top.h

diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 2589f4acd5ae..09fbfd6304ba 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -16,7 +16,8 @@ sun8i-drm-hdmi-y += sun8i_hdmi_phy_clk.o

sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \
sun8i_vi_layer.o sun8i_ui_scaler.o \
- sun8i_vi_scaler.o sun8i_csc.o
+ sun8i_vi_scaler.o sun8i_csc.o \
+ sun8i_tcon_top.o

sun4i-tcon-y += sun4i_crtc.o
sun4i-tcon-y += sun4i_dotclock.o
diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
new file mode 100644
index 000000000000..075a356a6dfa
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (c) 2018 Jernej Skrabec <[email protected]> */
+
+#include <drm/drmP.h>
+
+#include <dt-bindings/clock/sun8i-tcon-top.h>
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/spinlock.h>
+
+#include "sun8i_tcon_top.h"
+
+#define TCON_TOP_PORT_SEL_REG 0x1C
+#define TCON_TOP_PORT_DE0_MSK GENMASK(1, 0)
+#define TCON_TOP_PORT_DE1_MSK GENMASK(5, 4)
+#define TCON_TOP_PORT_TCON_LCD0 0
+#define TCON_TOP_PORT_TCON_LCD1 1
+#define TCON_TOP_PORT_TCON_TV0 2
+#define TCON_TOP_PORT_TCON_TV1 3
+
+#define TCON_TOP_GATE_SRC_REG 0x20
+#define TCON_TOP_HDMI_SRC_MSK GENMASK(29, 28)
+#define TCON_TOP_HDMI_SRC_NONE 0
+#define TCON_TOP_HDMI_SRC_TCON_TV0 1
+#define TCON_TOP_HDMI_SRC_TCON_TV1 2
+#define TCON_TOP_TCON_TV1_GATE 24
+#define TCON_TOP_TCON_TV0_GATE 20
+#define TCON_TOP_TCON_DSI_GATE 16
+
+#define CLK_NUM 3
+
+struct sun8i_tcon_top {
+ struct clk *bus;
+ void __iomem *regs;
+ struct reset_control *rst;
+
+ /*
+ * spinlock is used for locking access to registers from different
+ * places - tcon driver and clk subsystem.
+ */
+ spinlock_t reg_lock;
+};
+
+struct sun8i_tcon_top_gate {
+ const char *name;
+ u8 bit;
+ int index;
+};
+
+static const struct sun8i_tcon_top_gate gates[] = {
+ {"bus-tcon-top-dsi", TCON_TOP_TCON_DSI_GATE, CLK_BUS_TCON_TOP_DSI},
+ {"bus-tcon-top-tv0", TCON_TOP_TCON_TV0_GATE, CLK_BUS_TCON_TOP_TV0},
+ {"bus-tcon-top-tv1", TCON_TOP_TCON_TV1_GATE, CLK_BUS_TCON_TOP_TV1},
+};
+
+void sun8i_tcon_top_set_hdmi_src(struct sun8i_tcon_top *tcon_top, int tcon)
+{
+ unsigned long flags;
+ u32 val;
+
+ if (tcon > 1) {
+ DRM_ERROR("TCON index is too high!\n");
+ return;
+ }
+
+ spin_lock_irqsave(&tcon_top->reg_lock, flags);
+
+ val = readl(tcon_top->regs + TCON_TOP_GATE_SRC_REG);
+ val &= ~TCON_TOP_HDMI_SRC_MSK;
+ val |= FIELD_PREP(TCON_TOP_HDMI_SRC_MSK,
+ TCON_TOP_HDMI_SRC_TCON_TV0 + tcon);
+ writel(val, tcon_top->regs + TCON_TOP_GATE_SRC_REG);
+
+ spin_unlock_irqrestore(&tcon_top->reg_lock, flags);
+}
+
+void sun8i_tcon_top_de_config(struct sun8i_tcon_top *tcon_top,
+ int mixer, enum tcon_type tcon_type, int tcon)
+{
+ unsigned long flags;
+ u32 val, reg;
+
+ if (mixer > 1) {
+ DRM_ERROR("Mixer index is too high!\n");
+ return;
+ }
+
+ if (tcon > 1) {
+ DRM_ERROR("TCON index is too high!\n");
+ return;
+ }
+
+ switch (tcon_type) {
+ case tcon_type_lcd:
+ val = TCON_TOP_PORT_TCON_LCD0 + tcon;
+ break;
+ case tcon_type_tv:
+ val = TCON_TOP_PORT_TCON_TV0 + tcon;
+ break;
+ default:
+ DRM_ERROR("Invalid TCON type!\n");
+ return;
+ }
+
+ spin_lock_irqsave(&tcon_top->reg_lock, flags);
+
+ reg = readl(tcon_top->regs + TCON_TOP_PORT_SEL_REG);
+ if (mixer == 0) {
+ reg &= ~TCON_TOP_PORT_DE0_MSK;
+ reg |= FIELD_PREP(TCON_TOP_PORT_DE0_MSK, val);
+ } else {
+ reg &= ~TCON_TOP_PORT_DE1_MSK;
+ reg |= FIELD_PREP(TCON_TOP_PORT_DE1_MSK, val);
+ }
+ writel(reg, tcon_top->regs + TCON_TOP_PORT_SEL_REG);
+
+ spin_unlock_irqrestore(&tcon_top->reg_lock, flags);
+}
+
+static int sun8i_tcon_top_probe(struct platform_device *pdev)
+{
+ struct clk_hw_onecell_data *clk_data;
+ struct sun8i_tcon_top *tcon_top;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int ret, i;
+
+ tcon_top = devm_kzalloc(dev, sizeof(*tcon_top), GFP_KERNEL);
+ if (!tcon_top)
+ return -ENOMEM;
+
+ clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data) +
+ sizeof(*clk_data->hws) * CLK_NUM,
+ GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ spin_lock_init(&tcon_top->reg_lock);
+
+ tcon_top->rst = devm_reset_control_get(dev, "rst");
+ if (IS_ERR(tcon_top->rst)) {
+ dev_err(dev, "Couldn't get our reset line\n");
+ return PTR_ERR(tcon_top->rst);
+ }
+
+ tcon_top->bus = devm_clk_get(dev, "bus");
+ if (IS_ERR(tcon_top->bus)) {
+ dev_err(dev, "Couldn't get the bus clock\n");
+ return PTR_ERR(tcon_top->bus);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ tcon_top->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(tcon_top->regs))
+ return PTR_ERR(tcon_top->regs);
+
+ ret = reset_control_deassert(tcon_top->rst);
+ if (ret) {
+ dev_err(dev, "Could not deassert ctrl reset control\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(tcon_top->bus);
+ if (ret) {
+ dev_err(dev, "Could not enable bus clock\n");
+ goto err_assert_reset;
+ }
+
+ /*
+ * Default register values might have some reserved bits set, which
+ * prevents TCON TOP from working properly. Set them to 0 here.
+ */
+ writel(0, tcon_top->regs + TCON_TOP_PORT_SEL_REG);
+ writel(0, tcon_top->regs + TCON_TOP_GATE_SRC_REG);
+
+ for (i = 0; i < CLK_NUM; i++) {
+ const char *parent_name = "bus-tcon-top";
+ struct clk_init_data init;
+ struct clk_gate *gate;
+
+ gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
+ if (!gate) {
+ ret = -ENOMEM;
+ goto err_disable_clock;
+ }
+
+ init.name = gates[i].name;
+ init.ops = &clk_gate_ops;
+ init.flags = CLK_IS_BASIC;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ gate->reg = tcon_top->regs + TCON_TOP_GATE_SRC_REG;
+ gate->bit_idx = gates[i].bit;
+ gate->lock = &tcon_top->reg_lock;
+ gate->hw.init = &init;
+
+ ret = devm_clk_hw_register(dev, &gate->hw);
+ if (ret)
+ goto err_disable_clock;
+
+ clk_data->hws[gates[i].index] = &gate->hw;
+ }
+
+ clk_data->num = CLK_NUM;
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
+ if (ret)
+ goto err_disable_clock;
+
+ platform_set_drvdata(pdev, tcon_top);
+
+ return 0;
+
+err_disable_clock:
+ clk_disable_unprepare(tcon_top->bus);
+err_assert_reset:
+ reset_control_assert(tcon_top->rst);
+
+ return ret;
+}
+
+static int sun8i_tcon_top_remove(struct platform_device *pdev)
+{
+ struct sun8i_tcon_top *tcon_top = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(tcon_top->bus);
+ reset_control_assert(tcon_top->rst);
+
+ return 0;
+}
+
+const struct of_device_id sun8i_tcon_top_of_table[] = {
+ { .compatible = "allwinner,sun8i-r40-tcon-top" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sun8i_tcon_top_of_table);
+
+static struct platform_driver sun8i_tcon_top_platform_driver = {
+ .probe = sun8i_tcon_top_probe,
+ .remove = sun8i_tcon_top_remove,
+ .driver = {
+ .name = "sun8i-tcon-top",
+ .of_match_table = sun8i_tcon_top_of_table,
+ },
+};
+module_platform_driver(sun8i_tcon_top_platform_driver);
+
+MODULE_AUTHOR("Jernej Skrabec <[email protected]>");
+MODULE_DESCRIPTION("Allwinner R40 TCON TOP driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.h b/drivers/gpu/drm/sun4i/sun8i_tcon_top.h
new file mode 100644
index 000000000000..19126e07d2a6
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (c) 2018 Jernej Skrabec <[email protected]> */
+
+#ifndef _SUN8I_TCON_TOP_H_
+#define _SUN8I_TCON_TOP_H_
+
+#include <linux/device.h>
+
+struct sun8i_tcon_top;
+
+enum tcon_type {
+ tcon_type_lcd,
+ tcon_type_tv,
+};
+
+void sun8i_tcon_top_set_hdmi_src(struct sun8i_tcon_top *tcon_top, int tcon);
+void sun8i_tcon_top_de_config(struct sun8i_tcon_top *tcon_top,
+ int mixer, enum tcon_type tcon_type, int tcon);
+
+#endif /* _SUN8I_TCON_TOP_H_ */
diff --git a/include/dt-bindings/clock/sun8i-tcon-top.h b/include/dt-bindings/clock/sun8i-tcon-top.h
new file mode 100644
index 000000000000..c05e92770402
--- /dev/null
+++ b/include/dt-bindings/clock/sun8i-tcon-top.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/* Copyright (C) 2018 Jernej Skrabec <[email protected]> */
+
+#ifndef _DT_BINDINGS_CLOCK_SUN8I_TCON_TOP_H_
+#define _DT_BINDINGS_CLOCK_SUN8I_TCON_TOP_H_
+
+#define CLK_BUS_TCON_TOP_DSI 0
+#define CLK_BUS_TCON_TOP_TV0 1
+#define CLK_BUS_TCON_TOP_TV1 2
+
+#endif /* _DT_BINDINGS_CLOCK_SUN8I_TCON_TOP_H_ */
--
2.17.0


2018-05-19 18:37:00

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH 04/15] dt-bindings: display: sunxi-drm: Add TCON TOP description

TCON TOP main purpose is to configure whole display pipeline. It
determines relationships between mixers and TCONs, selects source TCON
for HDMI, muxes LCD and TV encoder GPIO output, selects TV encoder
clock source and contains additional TV TCON and DSI gates.

Signed-off-by: Jernej Skrabec <[email protected]>
---
.../bindings/display/sunxi/sun4i-drm.txt | 20 +++++++++++++++++++
1 file changed, 20 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
index 3346c1e2a7a0..a099957ab62a 100644
--- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
+++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
@@ -187,6 +187,26 @@ And on the A23, A31, A31s and A33, you need one more clock line:
- 'lvds-alt': An alternative clock source, separate from the TCON channel 0
clock, that can be used to drive the LVDS clock

+TCON TOP
+--------
+
+TCON TOPs main purpose is to configure whole display pipeline. It determines
+relationships between mixers and TCONs, selects source TCON for HDMI, muxes
+LCD and TV encoder GPIO output, selects TV encoder clock source and contains
+additional TV TCON and DSI gates.
+
+Required properties:
+ - compatible: value must be one of:
+ * allwinner,sun8i-r40-tcon-top
+ - reg: base address and size of the memory-mapped region.
+ - clocks: phandle to the clocks feeding the TCON TOP
+ * bus: TCON TOP interface clock
+ - clock-names: clock name mentioned above
+ - resets: phandle to the reset line driving the DRC
+ * rst: TCON TOP reset line
+ - reset-names: reset name mentioned above
+ - #clock-cells : must contain 1
+
DRC
---

--
2.17.0


2018-05-19 18:37:38

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH 03/15] clk: sunxi-ng: r40: Export video PLLs

Video PLLs need to be referenced in R40 DT as possible HDMI PHY parent.

Export them.

Signed-off-by: Jernej Skrabec <[email protected]>
---
drivers/clk/sunxi-ng/ccu-sun8i-r40.h | 8 ++++++--
include/dt-bindings/clock/sun8i-r40-ccu.h | 4 ++++
2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.h b/drivers/clk/sunxi-ng/ccu-sun8i-r40.h
index 0db8e1e97af8..db2a1243f9ff 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.h
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.h
@@ -25,7 +25,9 @@
#define CLK_PLL_AUDIO_2X 4
#define CLK_PLL_AUDIO_4X 5
#define CLK_PLL_AUDIO_8X 6
-#define CLK_PLL_VIDEO0 7
+
+/* PLL_VIDEO0 is exported */
+
#define CLK_PLL_VIDEO0_2X 8
#define CLK_PLL_VE 9
#define CLK_PLL_DDR0 10
@@ -34,7 +36,9 @@
#define CLK_PLL_PERIPH0_2X 13
#define CLK_PLL_PERIPH1 14
#define CLK_PLL_PERIPH1_2X 15
-#define CLK_PLL_VIDEO1 16
+
+/* PLL_VIDEO1 is exported */
+
#define CLK_PLL_VIDEO1_2X 17
#define CLK_PLL_SATA 18
#define CLK_PLL_SATA_OUT 19
diff --git a/include/dt-bindings/clock/sun8i-r40-ccu.h b/include/dt-bindings/clock/sun8i-r40-ccu.h
index 4fa5f69fc297..f9e15a235626 100644
--- a/include/dt-bindings/clock/sun8i-r40-ccu.h
+++ b/include/dt-bindings/clock/sun8i-r40-ccu.h
@@ -43,6 +43,10 @@
#ifndef _DT_BINDINGS_CLK_SUN8I_R40_H_
#define _DT_BINDINGS_CLK_SUN8I_R40_H_

+#define CLK_PLL_VIDEO0 7
+
+#define CLK_PLL_VIDEO1 16
+
#define CLK_CPU 24

#define CLK_BUS_MIPI_DSI 29
--
2.17.0


2018-05-20 01:51:20

by Julian Calaby

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH 07/15] dt-bindings: display: sun4i-drm: Add R40 HDMI pipeline

Hi Jernej,

On Sun, May 20, 2018 at 4:31 AM, Jernej Skrabec <[email protected]> wrote:
> Missing compatibles and descriptions needed to implement R40 HDMI
> pipeline are added.
>
> For mixers only compatibles are added.
>
> TCON description is expanded with R40 TV TCON compatibles. If the SoC
> has TCON TOP unit, phandle to that unit has to be specified. Additional
> clock has to be specified if SoC has TCON TOP and TCON is TV TCON.
>
> New compatible is added for DWC HDMI PHY, which has additional clock
> specified.

There's a bunch of A64 related stuff mixed in here, is the R40
compatible with the A64's parts? If so, you should probably mention
that in the commit log.

> Signed-off-by: Jernej Skrabec <[email protected]>
> ---
> .../bindings/display/sunxi/sun4i-drm.txt | 16 ++++++++++++++--
> 1 file changed, 14 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> index a099957ab62a..634276f713e8 100644
> --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> @@ -111,8 +112,9 @@ Required properties:
> - resets: phandle to the reset controller driving the PHY
> - reset-names: must be "phy"
>
> -H3 HDMI PHY requires additional clock:
> +H3 and A64 HDMI PHY requires additional clocks:
> - pll-0: parent of phy clock
> + - pll-1: second possible phy clock parent (A64 only)

Maybe split this into two:

H3 HDMI PHY ...
- pll-0: ...

A64 HDMI PHY ...
- pll-0: ...
- pll-1: ...

At the moment a quick reading implies that H3 needs pll-1.

Thanks,

--
Julian Calaby

Email: [email protected]
Profile: http://www.google.com/profiles/julian.calaby/

2018-05-20 01:58:41

by Julian Calaby

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH 10/15] drm/sun4i: Add support for R40 TV TCONs

Hi Jernej,

On Sun, May 20, 2018 at 4:31 AM, Jernej Skrabec <[email protected]> wrote:
> R40 display pipeline has a lot of possible configurations. HDMI can be
> connected to 2 different TCONs (out of 4) and mixers can be connected to
> any TCON. All this must be configured in TCON TOP.
>
> Along with definition of TCON capabilities also add mux callback, which
> can configure this complex pipeline.
>
> For now, only TCON TV is supported.
>
> Signed-off-by: Jernej Skrabec <[email protected]>
> ---
> drivers/gpu/drm/sun4i/sun4i_tcon.c | 39 ++++++++++++++++++++++++++++++
> 1 file changed, 39 insertions(+)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index e0c562ce1c22..81b9551e4f78 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -1274,6 +1274,31 @@ static int sun6i_tcon_set_mux(struct sun4i_tcon *tcon,
> return 0;
> }
>
> +static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon,
> + const struct drm_encoder *encoder,
> + int index)
> +{
> + if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
> + sun8i_tcon_top_set_hdmi_src(tcon->tcon_top, index);
> +
> + sun8i_tcon_top_de_config(tcon->tcon_top, tcon->id,
> + tcon_type_tv, index);
> +
> + return 0;
> +}
> +
> +static int sun8i_r40_tcon_tv_set_mux_0(struct sun4i_tcon *tcon,
> + const struct drm_encoder *encoder)
> +{
> + return sun8i_r40_tcon_tv_set_mux(tcon, encoder, 0);
> +}
> +
> +static int sun8i_r40_tcon_tv_set_mux_1(struct sun4i_tcon *tcon,
> + const struct drm_encoder *encoder)
> +{
> + return sun8i_r40_tcon_tv_set_mux(tcon, encoder, 1);
> +}

Are TCON-TOPs going to be a common thing in new SoCs from Allwinner?
If so, maybe we should add an index to the TCON quirks and have a
common TCON-TOP set_mux function.

Thanks,

--
Julian Calaby

Email: [email protected]
Profile: http://www.google.com/profiles/julian.calaby/

2018-05-20 02:10:40

by Julian Calaby

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH 10/15] drm/sun4i: Add support for R40 TV TCONs

Hi Jernej,

On Sun, May 20, 2018 at 11:57 AM, Julian Calaby <[email protected]> wrote:
> Hi Jernej,
>
> On Sun, May 20, 2018 at 4:31 AM, Jernej Skrabec <[email protected]> wrote:
>> R40 display pipeline has a lot of possible configurations. HDMI can be
>> connected to 2 different TCONs (out of 4) and mixers can be connected to
>> any TCON. All this must be configured in TCON TOP.
>>
>> Along with definition of TCON capabilities also add mux callback, which
>> can configure this complex pipeline.
>>
>> For now, only TCON TV is supported.
>>
>> Signed-off-by: Jernej Skrabec <[email protected]>
>> ---
>> drivers/gpu/drm/sun4i/sun4i_tcon.c | 39 ++++++++++++++++++++++++++++++
>> 1 file changed, 39 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
>> index e0c562ce1c22..81b9551e4f78 100644
>> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
>> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
>> @@ -1274,6 +1274,31 @@ static int sun6i_tcon_set_mux(struct sun4i_tcon *tcon,
>> return 0;
>> }
>>
>> +static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon,
>> + const struct drm_encoder *encoder,
>> + int index)
>> +{
>> + if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
>> + sun8i_tcon_top_set_hdmi_src(tcon->tcon_top, index);
>> +
>> + sun8i_tcon_top_de_config(tcon->tcon_top, tcon->id,
>> + tcon_type_tv, index);
>> +
>> + return 0;
>> +}
>> +
>> +static int sun8i_r40_tcon_tv_set_mux_0(struct sun4i_tcon *tcon,
>> + const struct drm_encoder *encoder)
>> +{
>> + return sun8i_r40_tcon_tv_set_mux(tcon, encoder, 0);
>> +}
>> +
>> +static int sun8i_r40_tcon_tv_set_mux_1(struct sun4i_tcon *tcon,
>> + const struct drm_encoder *encoder)
>> +{
>> + return sun8i_r40_tcon_tv_set_mux(tcon, encoder, 1);
>> +}
>
> Are TCON-TOPs going to be a common thing in new SoCs from Allwinner?
> If so, maybe we should add an index to the TCON quirks and have a
> common TCON-TOP set_mux function.

Actually, that only moves it up a level. Should it be a devicetree property?

Thanks,

--
Julian Calaby

Email: [email protected]
Profile: http://www.google.com/profiles/julian.calaby/

2018-05-20 07:31:31

by Jernej Skrabec

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH 10/15] drm/sun4i: Add support for R40 TV TCONs

Hi,

Dne nedelja, 20. maj 2018 ob 04:09:52 CEST je Julian Calaby napisal(a):
> Hi Jernej,
>
> On Sun, May 20, 2018 at 11:57 AM, Julian Calaby <[email protected]>
wrote:
> > Hi Jernej,
> >
> > On Sun, May 20, 2018 at 4:31 AM, Jernej Skrabec <[email protected]>
wrote:
> >> R40 display pipeline has a lot of possible configurations. HDMI can be
> >> connected to 2 different TCONs (out of 4) and mixers can be connected to
> >> any TCON. All this must be configured in TCON TOP.
> >>
> >> Along with definition of TCON capabilities also add mux callback, which
> >> can configure this complex pipeline.
> >>
> >> For now, only TCON TV is supported.
> >>
> >> Signed-off-by: Jernej Skrabec <[email protected]>
> >> ---
> >>
> >> drivers/gpu/drm/sun4i/sun4i_tcon.c | 39 ++++++++++++++++++++++++++++++
> >> 1 file changed, 39 insertions(+)
> >>
> >> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> >> b/drivers/gpu/drm/sun4i/sun4i_tcon.c index e0c562ce1c22..81b9551e4f78
> >> 100644
> >> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> >> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> >> @@ -1274,6 +1274,31 @@ static int sun6i_tcon_set_mux(struct sun4i_tcon
> >> *tcon,>>
> >> return 0;
> >>
> >> }
> >>
> >> +static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon,
> >> + const struct drm_encoder *encoder,
> >> + int index)
> >> +{
> >> + if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
> >> + sun8i_tcon_top_set_hdmi_src(tcon->tcon_top, index);
> >> +
> >> + sun8i_tcon_top_de_config(tcon->tcon_top, tcon->id,
> >> + tcon_type_tv, index);
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static int sun8i_r40_tcon_tv_set_mux_0(struct sun4i_tcon *tcon,
> >> + const struct drm_encoder *encoder)
> >> +{
> >> + return sun8i_r40_tcon_tv_set_mux(tcon, encoder, 0);
> >> +}
> >> +
> >> +static int sun8i_r40_tcon_tv_set_mux_1(struct sun4i_tcon *tcon,
> >> + const struct drm_encoder *encoder)
> >> +{
> >> + return sun8i_r40_tcon_tv_set_mux(tcon, encoder, 1);
> >> +}
> >
> > Are TCON-TOPs going to be a common thing in new SoCs from Allwinner?
> > If so, maybe we should add an index to the TCON quirks and have a
> > common TCON-TOP set_mux function.
>
> Actually, that only moves it up a level. Should it be a devicetree property?
>

TCON-TOP is besides R40 part of two newest Allwinner SoCs, H6 and A63.
However, they have only one TV TCON and one LCD TCON, so indexes are not
needed for them (always 0). This makes R40 somewhat special. I don't think it
makes sense to expand everything just for one SoC.

Best regards,
Jernej



2018-05-21 07:48:28

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 12/15] drm/sun4i: Add support for second clock parent to DW HDMI PHY clk driver

Hi Jernej,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on drm/drm-next]
[also build test WARNING on v4.17-rc6 next-20180517]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Jernej-Skrabec/Add-support-for-R40-HDMI-pipeline/20180521-131839
base: git://people.freedesktop.org/~airlied/linux.git drm-next
config: arm64-allmodconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm64

All warnings (new ones prefixed by >>):

In file included from drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h:12:0,
from drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c:9:
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c: In function 'sun8i_hdmi_phy_config_h3':
>> drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c:191:7: warning: large integer implicitly truncated to unsigned type [-Woverflow]
~SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK,
^
include/linux/regmap.h:76:36: note: in definition of macro 'regmap_update_bits'
regmap_update_bits_base(map, reg, mask, val, NULL, false, false)
^~~~

vim +191 drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c

8
> 9 #include "sun8i_dw_hdmi.h"
10
11 /*
12 * Address can be actually any value. Here is set to same value as
13 * it is set in BSP driver.
14 */
15 #define I2C_ADDR 0x69
16
17 static int sun8i_hdmi_phy_config_a83t(struct dw_hdmi *hdmi,
18 struct sun8i_hdmi_phy *phy,
19 unsigned int clk_rate)
20 {
21 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
22 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN,
23 SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN);
24
25 /* power down */
26 dw_hdmi_phy_gen2_txpwron(hdmi, 0);
27 dw_hdmi_phy_gen2_pddq(hdmi, 1);
28
29 dw_hdmi_phy_reset(hdmi);
30
31 dw_hdmi_phy_gen2_pddq(hdmi, 0);
32
33 dw_hdmi_phy_i2c_set_addr(hdmi, I2C_ADDR);
34
35 /*
36 * Values are taken from BSP HDMI driver. Although AW didn't
37 * release any documentation, explanation of this values can
38 * be found in i.MX 6Dual/6Quad Reference Manual.
39 */
40 if (clk_rate <= 27000000) {
41 dw_hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
42 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
43 dw_hdmi_phy_i2c_write(hdmi, 0x08da, 0x10);
44 dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
45 dw_hdmi_phy_i2c_write(hdmi, 0x0318, 0x0e);
46 dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
47 } else if (clk_rate <= 74250000) {
48 dw_hdmi_phy_i2c_write(hdmi, 0x0540, 0x06);
49 dw_hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
50 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
51 dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
52 dw_hdmi_phy_i2c_write(hdmi, 0x02b5, 0x0e);
53 dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
54 } else if (clk_rate <= 148500000) {
55 dw_hdmi_phy_i2c_write(hdmi, 0x04a0, 0x06);
56 dw_hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
57 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
58 dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19);
59 dw_hdmi_phy_i2c_write(hdmi, 0x0021, 0x0e);
60 dw_hdmi_phy_i2c_write(hdmi, 0x8029, 0x09);
61 } else {
62 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x06);
63 dw_hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
64 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
65 dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19);
66 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x0e);
67 dw_hdmi_phy_i2c_write(hdmi, 0x802b, 0x09);
68 }
69
70 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x1e);
71 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
72 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x17);
73
74 dw_hdmi_phy_gen2_txpwron(hdmi, 1);
75
76 return 0;
77 }
78
79 static int sun8i_hdmi_phy_config_h3(struct dw_hdmi *hdmi,
80 struct sun8i_hdmi_phy *phy,
81 unsigned int clk_rate)
82 {
83 u32 pll_cfg1_init;
84 u32 pll_cfg2_init;
85 u32 ana_cfg1_end;
86 u32 ana_cfg2_init;
87 u32 ana_cfg3_init;
88 u32 b_offset = 0;
89 u32 val;
90
91 /* bandwidth / frequency independent settings */
92
93 pll_cfg1_init = SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN |
94 SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN |
95 SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(7) |
96 SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(1) |
97 SUN8I_HDMI_PHY_PLL_CFG1_PLLDBEN |
98 SUN8I_HDMI_PHY_PLL_CFG1_CS |
99 SUN8I_HDMI_PHY_PLL_CFG1_CP_S(2) |
100 SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63) |
101 SUN8I_HDMI_PHY_PLL_CFG1_BWS;
102
103 pll_cfg2_init = SUN8I_HDMI_PHY_PLL_CFG2_SV_H |
104 SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN_EN |
105 SUN8I_HDMI_PHY_PLL_CFG2_SDIV2;
106
107 ana_cfg1_end = SUN8I_HDMI_PHY_ANA_CFG1_REG_SVBH(1) |
108 SUN8I_HDMI_PHY_ANA_CFG1_AMP_OPT |
109 SUN8I_HDMI_PHY_ANA_CFG1_EMP_OPT |
110 SUN8I_HDMI_PHY_ANA_CFG1_AMPCK_OPT |
111 SUN8I_HDMI_PHY_ANA_CFG1_EMPCK_OPT |
112 SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL |
113 SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG |
114 SUN8I_HDMI_PHY_ANA_CFG1_REG_SCKTMDS |
115 SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN |
116 SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK |
117 SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL |
118 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK |
119 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
120 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
121 SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
122 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2 |
123 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
124 SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
125 SUN8I_HDMI_PHY_ANA_CFG1_CKEN |
126 SUN8I_HDMI_PHY_ANA_CFG1_LDOEN |
127 SUN8I_HDMI_PHY_ANA_CFG1_ENVBS |
128 SUN8I_HDMI_PHY_ANA_CFG1_ENBI;
129
130 ana_cfg2_init = SUN8I_HDMI_PHY_ANA_CFG2_M_EN |
131 SUN8I_HDMI_PHY_ANA_CFG2_REG_DENCK |
132 SUN8I_HDMI_PHY_ANA_CFG2_REG_DEN |
133 SUN8I_HDMI_PHY_ANA_CFG2_REG_CKSS(1) |
134 SUN8I_HDMI_PHY_ANA_CFG2_REG_CSMPS(1);
135
136 ana_cfg3_init = SUN8I_HDMI_PHY_ANA_CFG3_REG_WIRE(0x3e0) |
137 SUN8I_HDMI_PHY_ANA_CFG3_SDAEN |
138 SUN8I_HDMI_PHY_ANA_CFG3_SCLEN;
139
140 /* bandwidth / frequency dependent settings */
141 if (clk_rate <= 27000000) {
142 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
143 SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
144 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
145 SUN8I_HDMI_PHY_PLL_CFG2_S(4);
146 ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW;
147 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) |
148 SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal);
149 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(3) |
150 SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(5);
151 } else if (clk_rate <= 74250000) {
152 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
153 SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
154 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
155 SUN8I_HDMI_PHY_PLL_CFG2_S(5);
156 ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW;
157 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) |
158 SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal);
159 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(5) |
160 SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(7);
161 } else if (clk_rate <= 148500000) {
162 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
163 SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
164 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
165 SUN8I_HDMI_PHY_PLL_CFG2_S(6);
166 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK |
167 SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW |
168 SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(2);
169 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(7) |
170 SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(9);
171 } else {
172 b_offset = 2;
173 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63);
174 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(6) |
175 SUN8I_HDMI_PHY_PLL_CFG2_S(7);
176 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK |
177 SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW |
178 SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4);
179 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(9) |
180 SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(13);
181 }
182
183 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
184 SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK, 0);
185
186 /*
187 * NOTE: We have to be careful not to overwrite PHY parent
188 * clock selection bit and clock divider.
189 */
190 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
> 191 ~SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK,
192 pll_cfg1_init);
193 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG,
194 (u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK,
195 pll_cfg2_init);
196 usleep_range(10000, 15000);
197 regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG3_REG,
198 SUN8I_HDMI_PHY_PLL_CFG3_SOUT_DIV2);
199 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
200 SUN8I_HDMI_PHY_PLL_CFG1_PLLEN,
201 SUN8I_HDMI_PHY_PLL_CFG1_PLLEN);
202 msleep(100);
203
204 /* get B value */
205 regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val);
206 val = (val & SUN8I_HDMI_PHY_ANA_STS_B_OUT_MSK) >>
207 SUN8I_HDMI_PHY_ANA_STS_B_OUT_SHIFT;
208 val = min(val + b_offset, (u32)0x3f);
209
210 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
211 SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 |
212 SUN8I_HDMI_PHY_PLL_CFG1_REG_OD,
213 SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 |
214 SUN8I_HDMI_PHY_PLL_CFG1_REG_OD);
215 regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
216 SUN8I_HDMI_PHY_PLL_CFG1_B_IN_MSK,
217 val << SUN8I_HDMI_PHY_PLL_CFG1_B_IN_SHIFT);
218 msleep(100);
219 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, ana_cfg1_end);
220 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG2_REG, ana_cfg2_init);
221 regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG3_REG, ana_cfg3_init);
222
223 return 0;
224 }
225

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (10.89 kB)
.config.gz (57.65 kB)
Download all attachments

2018-05-21 08:04:51

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 04/15] dt-bindings: display: sunxi-drm: Add TCON TOP description

Hi,

On Sat, May 19, 2018 at 08:31:16PM +0200, Jernej Skrabec wrote:
> TCON TOP main purpose is to configure whole display pipeline. It
> determines relationships between mixers and TCONs, selects source TCON
> for HDMI, muxes LCD and TV encoder GPIO output,

I'm not sure you mean GPIO here, but rather pin?

> selects TV encoder clock source and contains additional TV TCON and
> DSI gates.
>
> Signed-off-by: Jernej Skrabec <[email protected]>
> ---
> .../bindings/display/sunxi/sun4i-drm.txt | 20 +++++++++++++++++++
> 1 file changed, 20 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> index 3346c1e2a7a0..a099957ab62a 100644
> --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> @@ -187,6 +187,26 @@ And on the A23, A31, A31s and A33, you need one more clock line:
> - 'lvds-alt': An alternative clock source, separate from the TCON channel 0
> clock, that can be used to drive the LVDS clock
>
> +TCON TOP
> +--------
> +
> +TCON TOPs main purpose is to configure whole display pipeline. It determines
> +relationships between mixers and TCONs, selects source TCON for HDMI, muxes
> +LCD and TV encoder GPIO output, selects TV encoder clock source and contains
> +additional TV TCON and DSI gates.
> +
> +Required properties:
> + - compatible: value must be one of:
> + * allwinner,sun8i-r40-tcon-top
> + - reg: base address and size of the memory-mapped region.
> + - clocks: phandle to the clocks feeding the TCON TOP
> + * bus: TCON TOP interface clock
> + - clock-names: clock name mentioned above
> + - resets: phandle to the reset line driving the DRC
> + * rst: TCON TOP reset line
> + - reset-names: reset name mentioned above
> + - #clock-cells : must contain 1
> +

I guess you should better describe the OF-graph endpoints, and the
clocks output. Just using the binding additions here doesn't allow to
get a clear idea of how the DT should look like.

Maxime

--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com


Attachments:
(No filename) (2.24 kB)
signature.asc (849.00 B)
Download all attachments

2018-05-21 08:06:05

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 05/15] drm/sun4i: Add TCON TOP driver

On Sat, May 19, 2018 at 08:31:17PM +0200, Jernej Skrabec wrote:
> As already described in DT binding, TCON TOP is responsible for
> configuring display pipeline. In this initial driver focus is on HDMI
> pipeline, so TVE and LCD configuration is not implemented.
>
> Implemented features:
> - HDMI source selection
> - clock driver (TCON and DSI gating)
> - connecting mixers and TCONS
>
> Something similar also existed in previous SoCs, except that it was part
> of first TCON.
>
> Signed-off-by: Jernej Skrabec <[email protected]>
> ---
> drivers/gpu/drm/sun4i/Makefile | 3 +-
> drivers/gpu/drm/sun4i/sun8i_tcon_top.c | 256 +++++++++++++++++++++
> drivers/gpu/drm/sun4i/sun8i_tcon_top.h | 20 ++
> include/dt-bindings/clock/sun8i-tcon-top.h | 11 +
> 4 files changed, 289 insertions(+), 1 deletion(-)
> create mode 100644 drivers/gpu/drm/sun4i/sun8i_tcon_top.c
> create mode 100644 drivers/gpu/drm/sun4i/sun8i_tcon_top.h
> create mode 100644 include/dt-bindings/clock/sun8i-tcon-top.h
>
> diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> index 2589f4acd5ae..09fbfd6304ba 100644
> --- a/drivers/gpu/drm/sun4i/Makefile
> +++ b/drivers/gpu/drm/sun4i/Makefile
> @@ -16,7 +16,8 @@ sun8i-drm-hdmi-y += sun8i_hdmi_phy_clk.o
>
> sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \
> sun8i_vi_layer.o sun8i_ui_scaler.o \
> - sun8i_vi_scaler.o sun8i_csc.o
> + sun8i_vi_scaler.o sun8i_csc.o \
> + sun8i_tcon_top.o
>
> sun4i-tcon-y += sun4i_crtc.o
> sun4i-tcon-y += sun4i_dotclock.o
> diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
> new file mode 100644
> index 000000000000..075a356a6dfa
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
> @@ -0,0 +1,256 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/* Copyright (c) 2018 Jernej Skrabec <[email protected]> */
> +
> +#include <drm/drmP.h>
> +
> +#include <dt-bindings/clock/sun8i-tcon-top.h>
> +
> +#include <linux/bitfield.h>
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset.h>
> +#include <linux/spinlock.h>
> +
> +#include "sun8i_tcon_top.h"
> +
> +#define TCON_TOP_PORT_SEL_REG 0x1C
> +#define TCON_TOP_PORT_DE0_MSK GENMASK(1, 0)
> +#define TCON_TOP_PORT_DE1_MSK GENMASK(5, 4)
> +#define TCON_TOP_PORT_TCON_LCD0 0
> +#define TCON_TOP_PORT_TCON_LCD1 1
> +#define TCON_TOP_PORT_TCON_TV0 2
> +#define TCON_TOP_PORT_TCON_TV1 3
> +
> +#define TCON_TOP_GATE_SRC_REG 0x20
> +#define TCON_TOP_HDMI_SRC_MSK GENMASK(29, 28)
> +#define TCON_TOP_HDMI_SRC_NONE 0
> +#define TCON_TOP_HDMI_SRC_TCON_TV0 1
> +#define TCON_TOP_HDMI_SRC_TCON_TV1 2
> +#define TCON_TOP_TCON_TV1_GATE 24
> +#define TCON_TOP_TCON_TV0_GATE 20
> +#define TCON_TOP_TCON_DSI_GATE 16
> +
> +#define CLK_NUM 3
> +
> +struct sun8i_tcon_top {
> + struct clk *bus;
> + void __iomem *regs;
> + struct reset_control *rst;
> +
> + /*
> + * spinlock is used for locking access to registers from different
> + * places - tcon driver and clk subsystem.
> + */
> + spinlock_t reg_lock;
> +};
> +
> +struct sun8i_tcon_top_gate {
> + const char *name;
> + u8 bit;
> + int index;
> +};
> +
> +static const struct sun8i_tcon_top_gate gates[] = {
> + {"bus-tcon-top-dsi", TCON_TOP_TCON_DSI_GATE, CLK_BUS_TCON_TOP_DSI},
> + {"bus-tcon-top-tv0", TCON_TOP_TCON_TV0_GATE, CLK_BUS_TCON_TOP_TV0},
> + {"bus-tcon-top-tv1", TCON_TOP_TCON_TV1_GATE, CLK_BUS_TCON_TOP_TV1},
> +};
> +
> +void sun8i_tcon_top_set_hdmi_src(struct sun8i_tcon_top *tcon_top, int tcon)
> +{
> + unsigned long flags;
> + u32 val;
> +
> + if (tcon > 1) {
> + DRM_ERROR("TCON index is too high!\n");
> + return;
> + }
> +
> + spin_lock_irqsave(&tcon_top->reg_lock, flags);
> +
> + val = readl(tcon_top->regs + TCON_TOP_GATE_SRC_REG);
> + val &= ~TCON_TOP_HDMI_SRC_MSK;
> + val |= FIELD_PREP(TCON_TOP_HDMI_SRC_MSK,
> + TCON_TOP_HDMI_SRC_TCON_TV0 + tcon);
> + writel(val, tcon_top->regs + TCON_TOP_GATE_SRC_REG);
> +
> + spin_unlock_irqrestore(&tcon_top->reg_lock, flags);
> +}
> +
> +void sun8i_tcon_top_de_config(struct sun8i_tcon_top *tcon_top,
> + int mixer, enum tcon_type tcon_type, int tcon)
> +{
> + unsigned long flags;
> + u32 val, reg;
> +
> + if (mixer > 1) {
> + DRM_ERROR("Mixer index is too high!\n");
> + return;
> + }
> +
> + if (tcon > 1) {
> + DRM_ERROR("TCON index is too high!\n");
> + return;
> + }
> +
> + switch (tcon_type) {
> + case tcon_type_lcd:
> + val = TCON_TOP_PORT_TCON_LCD0 + tcon;
> + break;
> + case tcon_type_tv:
> + val = TCON_TOP_PORT_TCON_TV0 + tcon;
> + break;
> + default:
> + DRM_ERROR("Invalid TCON type!\n");
> + return;
> + }
> +
> + spin_lock_irqsave(&tcon_top->reg_lock, flags);
> +
> + reg = readl(tcon_top->regs + TCON_TOP_PORT_SEL_REG);
> + if (mixer == 0) {
> + reg &= ~TCON_TOP_PORT_DE0_MSK;
> + reg |= FIELD_PREP(TCON_TOP_PORT_DE0_MSK, val);
> + } else {
> + reg &= ~TCON_TOP_PORT_DE1_MSK;
> + reg |= FIELD_PREP(TCON_TOP_PORT_DE1_MSK, val);
> + }
> + writel(reg, tcon_top->regs + TCON_TOP_PORT_SEL_REG);
> +
> + spin_unlock_irqrestore(&tcon_top->reg_lock, flags);
> +}
> +
> +static int sun8i_tcon_top_probe(struct platform_device *pdev)
> +{
> + struct clk_hw_onecell_data *clk_data;
> + struct sun8i_tcon_top *tcon_top;
> + struct device *dev = &pdev->dev;
> + struct resource *res;
> + int ret, i;
> +
> + tcon_top = devm_kzalloc(dev, sizeof(*tcon_top), GFP_KERNEL);
> + if (!tcon_top)
> + return -ENOMEM;
> +
> + clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data) +
> + sizeof(*clk_data->hws) * CLK_NUM,
> + GFP_KERNEL);
> + if (!clk_data)
> + return -ENOMEM;
> +
> + spin_lock_init(&tcon_top->reg_lock);
> +
> + tcon_top->rst = devm_reset_control_get(dev, "rst");
> + if (IS_ERR(tcon_top->rst)) {
> + dev_err(dev, "Couldn't get our reset line\n");
> + return PTR_ERR(tcon_top->rst);
> + }
> +
> + tcon_top->bus = devm_clk_get(dev, "bus");
> + if (IS_ERR(tcon_top->bus)) {
> + dev_err(dev, "Couldn't get the bus clock\n");
> + return PTR_ERR(tcon_top->bus);
> + }
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + tcon_top->regs = devm_ioremap_resource(dev, res);
> + if (IS_ERR(tcon_top->regs))
> + return PTR_ERR(tcon_top->regs);
> +
> + ret = reset_control_deassert(tcon_top->rst);
> + if (ret) {
> + dev_err(dev, "Could not deassert ctrl reset control\n");
> + return ret;
> + }
> +
> + ret = clk_prepare_enable(tcon_top->bus);
> + if (ret) {
> + dev_err(dev, "Could not enable bus clock\n");
> + goto err_assert_reset;
> + }
> +
> + /*
> + * Default register values might have some reserved bits set, which
> + * prevents TCON TOP from working properly. Set them to 0 here.
> + */
> + writel(0, tcon_top->regs + TCON_TOP_PORT_SEL_REG);
> + writel(0, tcon_top->regs + TCON_TOP_GATE_SRC_REG);
> +
> + for (i = 0; i < CLK_NUM; i++) {
> + const char *parent_name = "bus-tcon-top";

I guess retrieving the parent's clock name at runtime would be more
flexible.

> + struct clk_init_data init;
> + struct clk_gate *gate;
> +
> + gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
> + if (!gate) {
> + ret = -ENOMEM;
> + goto err_disable_clock;
> + }
> +
> + init.name = gates[i].name;
> + init.ops = &clk_gate_ops;
> + init.flags = CLK_IS_BASIC;
> + init.parent_names = &parent_name;
> + init.num_parents = 1;
> +
> + gate->reg = tcon_top->regs + TCON_TOP_GATE_SRC_REG;
> + gate->bit_idx = gates[i].bit;
> + gate->lock = &tcon_top->reg_lock;
> + gate->hw.init = &init;
> +
> + ret = devm_clk_hw_register(dev, &gate->hw);
> + if (ret)
> + goto err_disable_clock;

Isn't it what clk_hw_register_gate is doing?

> + clk_data->hws[gates[i].index] = &gate->hw;
> + }
> +
> + clk_data->num = CLK_NUM;
> +
> + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data);
> + if (ret)
> + goto err_disable_clock;
> +
> + platform_set_drvdata(pdev, tcon_top);
> +
> + return 0;
> +
> +err_disable_clock:
> + clk_disable_unprepare(tcon_top->bus);
> +err_assert_reset:
> + reset_control_assert(tcon_top->rst);
> +
> + return ret;
> +}
> +
> +static int sun8i_tcon_top_remove(struct platform_device *pdev)
> +{
> + struct sun8i_tcon_top *tcon_top = platform_get_drvdata(pdev);
> +
> + clk_disable_unprepare(tcon_top->bus);
> + reset_control_assert(tcon_top->rst);
> +
> + return 0;
> +}
> +
> +const struct of_device_id sun8i_tcon_top_of_table[] = {
> + { .compatible = "allwinner,sun8i-r40-tcon-top" },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, sun8i_tcon_top_of_table);
> +
> +static struct platform_driver sun8i_tcon_top_platform_driver = {
> + .probe = sun8i_tcon_top_probe,
> + .remove = sun8i_tcon_top_remove,
> + .driver = {
> + .name = "sun8i-tcon-top",
> + .of_match_table = sun8i_tcon_top_of_table,
> + },
> +};
> +module_platform_driver(sun8i_tcon_top_platform_driver);
> +
> +MODULE_AUTHOR("Jernej Skrabec <[email protected]>");
> +MODULE_DESCRIPTION("Allwinner R40 TCON TOP driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.h b/drivers/gpu/drm/sun4i/sun8i_tcon_top.h
> new file mode 100644
> index 000000000000..19126e07d2a6
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/* Copyright (c) 2018 Jernej Skrabec <[email protected]> */
> +
> +#ifndef _SUN8I_TCON_TOP_H_
> +#define _SUN8I_TCON_TOP_H_
> +
> +#include <linux/device.h>
> +
> +struct sun8i_tcon_top;
> +
> +enum tcon_type {
> + tcon_type_lcd,
> + tcon_type_tv,

The usual practice is to have the enum values upper-case.

Thanks!
Maxime

--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com


Attachments:
(No filename) (9.88 kB)
signature.asc (849.00 B)
Download all attachments

2018-05-21 08:08:46

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 06/15] drm/sun4i: tcon: Add support for tcon-top

On Sat, May 19, 2018 at 08:31:18PM +0200, Jernej Skrabec wrote:
> If SoC has TCON TOP unit, it has to be configured from TCON, since it
> has all information needed. Additionally, if it is TCON TV, it must also
> enable bus gate inside TCON TOP unit.

Why?

> Add support for such TCONs.
>
> Signed-off-by: Jernej Skrabec <[email protected]>
> ---
> drivers/gpu/drm/sun4i/sun4i_tcon.c | 28 ++++++++++++++++++++++++++++
> drivers/gpu/drm/sun4i/sun4i_tcon.h | 8 ++++++++
> 2 files changed, 36 insertions(+)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index 08747fc3ee71..e0c562ce1c22 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -688,6 +688,16 @@ static int sun4i_tcon_init_clocks(struct device *dev,
> dev_err(dev, "Couldn't get the TCON bus clock\n");
> return PTR_ERR(tcon->clk);
> }
> +
> + if (tcon->quirks->needs_tcon_top && tcon->quirks->has_channel_1) {
> + tcon->top_clk = devm_clk_get(dev, "tcon-top");
> + if (IS_ERR(tcon->top_clk)) {
> + dev_err(dev, "Couldn't get the TCON TOP bus clock\n");
> + return PTR_ERR(tcon->top_clk);
> + }
> + clk_prepare_enable(tcon->top_clk);
> + }
> +
> clk_prepare_enable(tcon->clk);
>
> if (tcon->quirks->has_channel_0) {
> @@ -712,6 +722,7 @@ static int sun4i_tcon_init_clocks(struct device *dev,
> static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
> {
> clk_disable_unprepare(tcon->clk);
> + clk_disable_unprepare(tcon->top_clk);
> }
>
> static int sun4i_tcon_init_irq(struct device *dev,
> @@ -980,6 +991,23 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
> tcon->id = engine->id;
> tcon->quirks = of_device_get_match_data(dev);
>
> + if (tcon->quirks->needs_tcon_top) {
> + struct device_node *np;
> +
> + np = of_parse_phandle(dev->of_node, "allwinner,tcon-top", 0);
> + if (np) {
> + struct platform_device *pdev;
> +
> + pdev = of_find_device_by_node(np);
> + if (pdev)
> + tcon->tcon_top = platform_get_drvdata(pdev);
> + of_node_put(np);
> +
> + if (!tcon->tcon_top)
> + return -EPROBE_DEFER;
> + }
> + }
> +

I might have missed it, but I've not seen the bindings additions for
that property. This shouldn't really be done that way anyway, instead
of using a direct phandle, you should be using the of-graph, with the
TCON-top sitting where it belongs in the flow of data.

Maxime

--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com


Attachments:
(No filename) (2.56 kB)
signature.asc (849.00 B)
Download all attachments

2018-05-21 08:13:53

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 12/15] drm/sun4i: Add support for second clock parent to DW HDMI PHY clk driver

On Sat, May 19, 2018 at 08:31:24PM +0200, Jernej Skrabec wrote:
> Expand HDMI PHY clock driver to support second clock parent.
>
> Signed-off-by: Jernej Skrabec <[email protected]>
> ---
> drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 6 +-
> drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 29 ++++++-
> drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c | 90 ++++++++++++++++------
> 3 files changed, 98 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
> index 801a17222762..aadbe0a10b0c 100644
> --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
> +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
> @@ -98,7 +98,8 @@
> #define SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN BIT(29)
> #define SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN BIT(28)
> #define SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 BIT(27)
> -#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL BIT(26)
> +#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK BIT(26)
> +#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT 26
> #define SUN8I_HDMI_PHY_PLL_CFG1_PLLEN BIT(25)
> #define SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(x) ((x) << 22)
> #define SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(x) ((x) << 20)
> @@ -190,6 +191,7 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi);
> void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
> const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void);
>
> -int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev);
> +int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev,
> + bool second_parent);
>
> #endif /* _SUN8I_DW_HDMI_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
> index deba47ed69d8..7a911f0a3ae3 100644
> --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
> +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
> @@ -183,7 +183,13 @@ static int sun8i_hdmi_phy_config_h3(struct dw_hdmi *hdmi,
> regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
> SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK, 0);
>
> - regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, pll_cfg1_init);
> + /*
> + * NOTE: We have to be careful not to overwrite PHY parent
> + * clock selection bit and clock divider.
> + */
> + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
> + ~SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK,
> + pll_cfg1_init);

It feels like it belongs in a separate patch.

> regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG,
> (u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK,
> pll_cfg2_init);
> @@ -352,6 +358,10 @@ static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
> SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
> SUN8I_HDMI_PHY_ANA_CFG3_SDAEN);
>
> + /* reset PLL clock configuration */
> + regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 0);
> + regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG, 0);
> +

Ditto,

> +
> + /*
> + * Even though HDMI PHY clock doesn't have enable/disable
> + * handlers, we have to enable it. Otherwise it could happen
> + * that parent PLL is not enabled by clock framework in a
> + * highly unlikely event when parent PLL is used solely for
> + * HDMI PHY clock.
> + */
> + clk_prepare_enable(phy->clk_phy);

The implementation of the clock doesn't really matter in our API
usage. If we're using a clock, we have to call
clk_prepare_enable. That's documented everywhere, and mentionning how
the clock is implemented is an abstraction leakage and it's
irrelevant. I'd simply remove the comment here.

And it should be in a separate patch as well.

Maxime

--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com


Attachments:
(No filename) (3.68 kB)
signature.asc (849.00 B)
Download all attachments

2018-05-21 15:11:47

by Jernej Skrabec

[permalink] [raw]
Subject: Re: [linux-sunxi] Re: [PATCH 12/15] drm/sun4i: Add support for second clock parent to DW HDMI PHY clk driver

Hi,

Dne ponedeljek, 21. maj 2018 ob 10:12:53 CEST je Maxime Ripard napisal(a):
> On Sat, May 19, 2018 at 08:31:24PM +0200, Jernej Skrabec wrote:
> > Expand HDMI PHY clock driver to support second clock parent.
> >
> > Signed-off-by: Jernej Skrabec <[email protected]>
> > ---
> >
> > drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 6 +-
> > drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 29 ++++++-
> > drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c | 90 ++++++++++++++++------
> > 3 files changed, 98 insertions(+), 27 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
> > b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h index 801a17222762..aadbe0a10b0c
> > 100644
> > --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
> > +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
> > @@ -98,7 +98,8 @@
> >
> > #define SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN BIT(29)
> > #define SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN BIT(28)
> > #define SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 BIT(27)
> >
> > -#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL BIT(26)
> > +#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK BIT(26)
> > +#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT 26
> >
> > #define SUN8I_HDMI_PHY_PLL_CFG1_PLLEN BIT(25)
> > #define SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(x) ((x) << 22)
> > #define SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(x) ((x) << 20)
> >
> > @@ -190,6 +191,7 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi
> > *hdmi);
> >
> > void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
> > const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void);
> >
> > -int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev);
> > +int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev,
> > + bool second_parent);
> >
> > #endif /* _SUN8I_DW_HDMI_H_ */
> >
> > diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
> > b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index deba47ed69d8..7a911f0a3ae3
> > 100644
> > --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
> > +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
> > @@ -183,7 +183,13 @@ static int sun8i_hdmi_phy_config_h3(struct dw_hdmi
> > *hdmi,>
> > regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
> >
> > SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK, 0);
> >
> > - regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, pll_cfg1_init);
> > + /*
> > + * NOTE: We have to be careful not to overwrite PHY parent
> > + * clock selection bit and clock divider.
> > + */
> > + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
> > + ~SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK,
> > + pll_cfg1_init);
>
> It feels like it belongs in a separate patch.

Why? clk_set_rate() on HDMI PHY clock is called before this function, so
SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL bit is already set to correct value. Original
code doesn't take this into account and sets it to 0 here in all cases, which
obviously is not right.

If you insist on splitting this in new patch, it has to be applied before
clock changes. It would also need to include "reset PLL clock configuration"
chunk (next change in this patch), otherwise other SoCs with only one parent
could get 1 there, which is obviously wrong. Note that I didn't really tested
if default value of this bit is 0 or 1, but I wouldn't really like to depend
on default values.

>
> > regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG,
> >
> > (u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK,
> > pll_cfg2_init);
> >
> > @@ -352,6 +358,10 @@ static void sun8i_hdmi_phy_init_h3(struct
> > sun8i_hdmi_phy *phy)>
> > SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
> > SUN8I_HDMI_PHY_ANA_CFG3_SDAEN);
> >
> > + /* reset PLL clock configuration */
> > + regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 0);
> > + regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG, 0);
> > +
>
> Ditto,
>
> > +
> > + /*
> > + * Even though HDMI PHY clock doesn't have enable/disable
> > + * handlers, we have to enable it. Otherwise it could happen
> > + * that parent PLL is not enabled by clock framework in a
> > + * highly unlikely event when parent PLL is used solely for
> > + * HDMI PHY clock.
> > + */
> > + clk_prepare_enable(phy->clk_phy);
>
> The implementation of the clock doesn't really matter in our API
> usage. If we're using a clock, we have to call
> clk_prepare_enable. That's documented everywhere, and mentionning how
> the clock is implemented is an abstraction leakage and it's
> irrelevant. I'd simply remove the comment here.
>
> And it should be in a separate patch as well.

OK. Should I add Fixes tag, since current code obviously is not by the specs?
It could still get in 4.17...

Best regards,
Jernej



2018-05-21 15:12:55

by Jernej Skrabec

[permalink] [raw]
Subject: Re: [PATCH 04/15] dt-bindings: display: sunxi-drm: Add TCON TOP description

Hi,

Dne ponedeljek, 21. maj 2018 ob 10:01:47 CEST je Maxime Ripard napisal(a):
> Hi,
>
> On Sat, May 19, 2018 at 08:31:16PM +0200, Jernej Skrabec wrote:
> > TCON TOP main purpose is to configure whole display pipeline. It
> > determines relationships between mixers and TCONs, selects source TCON
> > for HDMI, muxes LCD and TV encoder GPIO output,
>
> I'm not sure you mean GPIO here, but rather pin?

Right, I'll fix that.

>
> > selects TV encoder clock source and contains additional TV TCON and
> > DSI gates.
> >
> > Signed-off-by: Jernej Skrabec <[email protected]>
> > ---
> >
> > .../bindings/display/sunxi/sun4i-drm.txt | 20 +++++++++++++++++++
> > 1 file changed, 20 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> > b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index
> > 3346c1e2a7a0..a099957ab62a 100644
> > --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> > +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> >
> > @@ -187,6 +187,26 @@ And on the A23, A31, A31s and A33, you need one more
clock line:
> > - 'lvds-alt': An alternative clock source, separate from the TCON
> > channel 0
> >
> > clock, that can be used to drive the LVDS clock
> >
> > +TCON TOP
> > +--------
> > +
> > +TCON TOPs main purpose is to configure whole display pipeline. It
> > determines +relationships between mixers and TCONs, selects source TCON
> > for HDMI, muxes +LCD and TV encoder GPIO output, selects TV encoder clock
> > source and contains +additional TV TCON and DSI gates.
> > +
> > +Required properties:
> > + - compatible: value must be one of:
> > + * allwinner,sun8i-r40-tcon-top
> > + - reg: base address and size of the memory-mapped region.
> > + - clocks: phandle to the clocks feeding the TCON TOP
> > + * bus: TCON TOP interface clock
> > + - clock-names: clock name mentioned above
> > + - resets: phandle to the reset line driving the DRC
> > + * rst: TCON TOP reset line
> > + - reset-names: reset name mentioned above
> > + - #clock-cells : must contain 1
> > +
>
> I guess you should better describe the OF-graph endpoints, and the
> clocks output. Just using the binding additions here doesn't allow to
> get a clear idea of how the DT should look like.

With my idea of implementation, OF graph is the same as before, so I didn't
mention anything about it.

My idea of dependencies (you should view it in fixed width font):
TCON-TOP
^
|
mixer <-> TCON <-> HDMI

I'll explain my design decision as response to other mail.

Best regards,
Jernej



2018-05-21 15:16:43

by Jernej Skrabec

[permalink] [raw]
Subject: Re: [PATCH 05/15] drm/sun4i: Add TCON TOP driver

Hi,

Dne ponedeljek, 21. maj 2018 ob 10:05:17 CEST je Maxime Ripard napisal(a):
> On Sat, May 19, 2018 at 08:31:17PM +0200, Jernej Skrabec wrote:
> > As already described in DT binding, TCON TOP is responsible for
> > configuring display pipeline. In this initial driver focus is on HDMI
> > pipeline, so TVE and LCD configuration is not implemented.
> >
> > Implemented features:
> > - HDMI source selection
> > - clock driver (TCON and DSI gating)
> > - connecting mixers and TCONS
> >
> > Something similar also existed in previous SoCs, except that it was part
> > of first TCON.
> >
> > Signed-off-by: Jernej Skrabec <[email protected]>
> > ---
> >
> > drivers/gpu/drm/sun4i/Makefile | 3 +-
> > drivers/gpu/drm/sun4i/sun8i_tcon_top.c | 256 +++++++++++++++++++++
> > drivers/gpu/drm/sun4i/sun8i_tcon_top.h | 20 ++
> > include/dt-bindings/clock/sun8i-tcon-top.h | 11 +
> > 4 files changed, 289 insertions(+), 1 deletion(-)
> > create mode 100644 drivers/gpu/drm/sun4i/sun8i_tcon_top.c
> > create mode 100644 drivers/gpu/drm/sun4i/sun8i_tcon_top.h
> > create mode 100644 include/dt-bindings/clock/sun8i-tcon-top.h
> >
> > diff --git a/drivers/gpu/drm/sun4i/Makefile
> > b/drivers/gpu/drm/sun4i/Makefile index 2589f4acd5ae..09fbfd6304ba 100644
> > --- a/drivers/gpu/drm/sun4i/Makefile
> > +++ b/drivers/gpu/drm/sun4i/Makefile
> > @@ -16,7 +16,8 @@ sun8i-drm-hdmi-y += sun8i_hdmi_phy_clk.o
> >
> > sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \
> >
> > sun8i_vi_layer.o sun8i_ui_scaler.o \
> >
> > - sun8i_vi_scaler.o sun8i_csc.o
> > + sun8i_vi_scaler.o sun8i_csc.o \
> > + sun8i_tcon_top.o
> >
> > sun4i-tcon-y += sun4i_crtc.o
> > sun4i-tcon-y += sun4i_dotclock.o
> >
> > diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
> > b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c new file mode 100644
> > index 000000000000..075a356a6dfa
> > --- /dev/null
> > +++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
> > @@ -0,0 +1,256 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/* Copyright (c) 2018 Jernej Skrabec <[email protected]> */
> > +
> > +#include <drm/drmP.h>
> > +
> > +#include <dt-bindings/clock/sun8i-tcon-top.h>
> > +
> > +#include <linux/bitfield.h>
> > +#include <linux/clk.h>
> > +#include <linux/clk-provider.h>
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/reset.h>
> > +#include <linux/spinlock.h>
> > +
> > +#include "sun8i_tcon_top.h"
> > +
> > +#define TCON_TOP_PORT_SEL_REG 0x1C
> > +#define TCON_TOP_PORT_DE0_MSK GENMASK(1, 0)
> > +#define TCON_TOP_PORT_DE1_MSK GENMASK(5, 4)
> > +#define TCON_TOP_PORT_TCON_LCD0 0
> > +#define TCON_TOP_PORT_TCON_LCD1 1
> > +#define TCON_TOP_PORT_TCON_TV0 2
> > +#define TCON_TOP_PORT_TCON_TV1 3
> > +
> > +#define TCON_TOP_GATE_SRC_REG 0x20
> > +#define TCON_TOP_HDMI_SRC_MSK GENMASK(29, 28)
> > +#define TCON_TOP_HDMI_SRC_NONE 0
> > +#define TCON_TOP_HDMI_SRC_TCON_TV0 1
> > +#define TCON_TOP_HDMI_SRC_TCON_TV1 2
> > +#define TCON_TOP_TCON_TV1_GATE 24
> > +#define TCON_TOP_TCON_TV0_GATE 20
> > +#define TCON_TOP_TCON_DSI_GATE 16
> > +
> > +#define CLK_NUM 3
> > +
> > +struct sun8i_tcon_top {
> > + struct clk *bus;
> > + void __iomem *regs;
> > + struct reset_control *rst;
> > +
> > + /*
> > + * spinlock is used for locking access to registers from different
> > + * places - tcon driver and clk subsystem.
> > + */
> > + spinlock_t reg_lock;
> > +};
> > +
> > +struct sun8i_tcon_top_gate {
> > + const char *name;
> > + u8 bit;
> > + int index;
> > +};
> > +
> > +static const struct sun8i_tcon_top_gate gates[] = {
> > + {"bus-tcon-top-dsi", TCON_TOP_TCON_DSI_GATE, CLK_BUS_TCON_TOP_DSI},
> > + {"bus-tcon-top-tv0", TCON_TOP_TCON_TV0_GATE, CLK_BUS_TCON_TOP_TV0},
> > + {"bus-tcon-top-tv1", TCON_TOP_TCON_TV1_GATE, CLK_BUS_TCON_TOP_TV1},
> > +};
> > +
> > +void sun8i_tcon_top_set_hdmi_src(struct sun8i_tcon_top *tcon_top, int
> > tcon) +{
> > + unsigned long flags;
> > + u32 val;
> > +
> > + if (tcon > 1) {
> > + DRM_ERROR("TCON index is too high!\n");
> > + return;
> > + }
> > +
> > + spin_lock_irqsave(&tcon_top->reg_lock, flags);
> > +
> > + val = readl(tcon_top->regs + TCON_TOP_GATE_SRC_REG);
> > + val &= ~TCON_TOP_HDMI_SRC_MSK;
> > + val |= FIELD_PREP(TCON_TOP_HDMI_SRC_MSK,
> > + TCON_TOP_HDMI_SRC_TCON_TV0 + tcon);
> > + writel(val, tcon_top->regs + TCON_TOP_GATE_SRC_REG);
> > +
> > + spin_unlock_irqrestore(&tcon_top->reg_lock, flags);
> > +}
> > +
> > +void sun8i_tcon_top_de_config(struct sun8i_tcon_top *tcon_top,
> > + int mixer, enum tcon_type tcon_type, int tcon)
> > +{
> > + unsigned long flags;
> > + u32 val, reg;
> > +
> > + if (mixer > 1) {
> > + DRM_ERROR("Mixer index is too high!\n");
> > + return;
> > + }
> > +
> > + if (tcon > 1) {
> > + DRM_ERROR("TCON index is too high!\n");
> > + return;
> > + }
> > +
> > + switch (tcon_type) {
> > + case tcon_type_lcd:
> > + val = TCON_TOP_PORT_TCON_LCD0 + tcon;
> > + break;
> > + case tcon_type_tv:
> > + val = TCON_TOP_PORT_TCON_TV0 + tcon;
> > + break;
> > + default:
> > + DRM_ERROR("Invalid TCON type!\n");
> > + return;
> > + }
> > +
> > + spin_lock_irqsave(&tcon_top->reg_lock, flags);
> > +
> > + reg = readl(tcon_top->regs + TCON_TOP_PORT_SEL_REG);
> > + if (mixer == 0) {
> > + reg &= ~TCON_TOP_PORT_DE0_MSK;
> > + reg |= FIELD_PREP(TCON_TOP_PORT_DE0_MSK, val);
> > + } else {
> > + reg &= ~TCON_TOP_PORT_DE1_MSK;
> > + reg |= FIELD_PREP(TCON_TOP_PORT_DE1_MSK, val);
> > + }
> > + writel(reg, tcon_top->regs + TCON_TOP_PORT_SEL_REG);
> > +
> > + spin_unlock_irqrestore(&tcon_top->reg_lock, flags);
> > +}
> > +
> > +static int sun8i_tcon_top_probe(struct platform_device *pdev)
> > +{
> > + struct clk_hw_onecell_data *clk_data;
> > + struct sun8i_tcon_top *tcon_top;
> > + struct device *dev = &pdev->dev;
> > + struct resource *res;
> > + int ret, i;
> > +
> > + tcon_top = devm_kzalloc(dev, sizeof(*tcon_top), GFP_KERNEL);
> > + if (!tcon_top)
> > + return -ENOMEM;
> > +
> > + clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data) +
> > + sizeof(*clk_data->hws) * CLK_NUM,
> > + GFP_KERNEL);
> > + if (!clk_data)
> > + return -ENOMEM;
> > +
> > + spin_lock_init(&tcon_top->reg_lock);
> > +
> > + tcon_top->rst = devm_reset_control_get(dev, "rst");
> > + if (IS_ERR(tcon_top->rst)) {
> > + dev_err(dev, "Couldn't get our reset line\n");
> > + return PTR_ERR(tcon_top->rst);
> > + }
> > +
> > + tcon_top->bus = devm_clk_get(dev, "bus");
> > + if (IS_ERR(tcon_top->bus)) {
> > + dev_err(dev, "Couldn't get the bus clock\n");
> > + return PTR_ERR(tcon_top->bus);
> > + }
> > +
> > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > + tcon_top->regs = devm_ioremap_resource(dev, res);
> > + if (IS_ERR(tcon_top->regs))
> > + return PTR_ERR(tcon_top->regs);
> > +
> > + ret = reset_control_deassert(tcon_top->rst);
> > + if (ret) {
> > + dev_err(dev, "Could not deassert ctrl reset control\n");
> > + return ret;
> > + }
> > +
> > + ret = clk_prepare_enable(tcon_top->bus);
> > + if (ret) {
> > + dev_err(dev, "Could not enable bus clock\n");
> > + goto err_assert_reset;
> > + }
> > +
> > + /*
> > + * Default register values might have some reserved bits set, which
> > + * prevents TCON TOP from working properly. Set them to 0 here.
> > + */
> > + writel(0, tcon_top->regs + TCON_TOP_PORT_SEL_REG);
> > + writel(0, tcon_top->regs + TCON_TOP_GATE_SRC_REG);
> > +
> > + for (i = 0; i < CLK_NUM; i++) {
> > + const char *parent_name = "bus-tcon-top";
>
> I guess retrieving the parent's clock name at runtime would be more
> flexible.
>

It is, but will it ever be anything else?

> > + struct clk_init_data init;
> > + struct clk_gate *gate;
> > +
> > + gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
> > + if (!gate) {
> > + ret = -ENOMEM;
> > + goto err_disable_clock;
> > + }
> > +
> > + init.name = gates[i].name;
> > + init.ops = &clk_gate_ops;
> > + init.flags = CLK_IS_BASIC;
> > + init.parent_names = &parent_name;
> > + init.num_parents = 1;
> > +
> > + gate->reg = tcon_top->regs + TCON_TOP_GATE_SRC_REG;
> > + gate->bit_idx = gates[i].bit;
> > + gate->lock = &tcon_top->reg_lock;
> > + gate->hw.init = &init;
> > +
> > + ret = devm_clk_hw_register(dev, &gate->hw);
> > + if (ret)
> > + goto err_disable_clock;
>
> Isn't it what clk_hw_register_gate is doing?
>

Almost, but not exactly. My goal was to use devm_* functions, so there is no
need to do any special cleanup.

> > + clk_data->hws[gates[i].index] = &gate->hw;
> > + }
> > +
> > + clk_data->num = CLK_NUM;
> > +
> > + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
clk_data);
> > + if (ret)
> > + goto err_disable_clock;
> > +
> > + platform_set_drvdata(pdev, tcon_top);
> > +
> > + return 0;
> > +
> > +err_disable_clock:
> > + clk_disable_unprepare(tcon_top->bus);
> > +err_assert_reset:
> > + reset_control_assert(tcon_top->rst);
> > +
> > + return ret;
> > +}
> > +
> > +static int sun8i_tcon_top_remove(struct platform_device *pdev)
> > +{
> > + struct sun8i_tcon_top *tcon_top = platform_get_drvdata(pdev);
> > +
> > + clk_disable_unprepare(tcon_top->bus);
> > + reset_control_assert(tcon_top->rst);
> > +
> > + return 0;
> > +}
> > +
> > +const struct of_device_id sun8i_tcon_top_of_table[] = {
> > + { .compatible = "allwinner,sun8i-r40-tcon-top" },
> > + { /* sentinel */ }
> > +};
> > +MODULE_DEVICE_TABLE(of, sun8i_tcon_top_of_table);
> > +
> > +static struct platform_driver sun8i_tcon_top_platform_driver = {
> > + .probe = sun8i_tcon_top_probe,
> > + .remove = sun8i_tcon_top_remove,
> > + .driver = {
> > + .name = "sun8i-tcon-top",
> > + .of_match_table = sun8i_tcon_top_of_table,
> > + },
> > +};
> > +module_platform_driver(sun8i_tcon_top_platform_driver);
> > +
> > +MODULE_AUTHOR("Jernej Skrabec <[email protected]>");
> > +MODULE_DESCRIPTION("Allwinner R40 TCON TOP driver");
> > +MODULE_LICENSE("GPL");
> > diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.h
> > b/drivers/gpu/drm/sun4i/sun8i_tcon_top.h new file mode 100644
> > index 000000000000..19126e07d2a6
> > --- /dev/null
> > +++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.h
> > @@ -0,0 +1,20 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/* Copyright (c) 2018 Jernej Skrabec <[email protected]> */
> > +
> > +#ifndef _SUN8I_TCON_TOP_H_
> > +#define _SUN8I_TCON_TOP_H_
> > +
> > +#include <linux/device.h>
> > +
> > +struct sun8i_tcon_top;
> > +
> > +enum tcon_type {
> > + tcon_type_lcd,
> > + tcon_type_tv,
>
> The usual practice is to have the enum values upper-case.

Ok.

Best regards,
Jernej



2018-05-21 17:30:19

by Jernej Skrabec

[permalink] [raw]
Subject: Re: [PATCH 06/15] drm/sun4i: tcon: Add support for tcon-top

Hi,

Dne ponedeljek, 21. maj 2018 ob 10:07:59 CEST je Maxime Ripard napisal(a):
> On Sat, May 19, 2018 at 08:31:18PM +0200, Jernej Skrabec wrote:
> > If SoC has TCON TOP unit, it has to be configured from TCON, since it
> > has all information needed. Additionally, if it is TCON TV, it must also
> > enable bus gate inside TCON TOP unit.
>
> Why?

I'll explain my design decision below.

>
> > Add support for such TCONs.
> >
> > Signed-off-by: Jernej Skrabec <[email protected]>
> > ---
> >
> > drivers/gpu/drm/sun4i/sun4i_tcon.c | 28 ++++++++++++++++++++++++++++
> > drivers/gpu/drm/sun4i/sun4i_tcon.h | 8 ++++++++
> > 2 files changed, 36 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 08747fc3ee71..e0c562ce1c22
> > 100644
> > --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > @@ -688,6 +688,16 @@ static int sun4i_tcon_init_clocks(struct device *dev,
> >
> > dev_err(dev, "Couldn't get the TCON bus clock\n");
> > return PTR_ERR(tcon->clk);
> >
> > }
> >
> > +
> > + if (tcon->quirks->needs_tcon_top && tcon->quirks->has_channel_1) {
> > + tcon->top_clk = devm_clk_get(dev, "tcon-top");
> > + if (IS_ERR(tcon->top_clk)) {
> > + dev_err(dev, "Couldn't get the TCON TOP bus clock\n");
> > + return PTR_ERR(tcon->top_clk);
> > + }
> > + clk_prepare_enable(tcon->top_clk);
> > + }
> > +
> >
> > clk_prepare_enable(tcon->clk);
> >
> > if (tcon->quirks->has_channel_0) {
> >
> > @@ -712,6 +722,7 @@ static int sun4i_tcon_init_clocks(struct device *dev,
> >
> > static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
> > {
> >
> > clk_disable_unprepare(tcon->clk);
> >
> > + clk_disable_unprepare(tcon->top_clk);
> >
> > }
> >
> > static int sun4i_tcon_init_irq(struct device *dev,
> >
> > @@ -980,6 +991,23 @@ static int sun4i_tcon_bind(struct device *dev, struct
> > device *master,>
> > tcon->id = engine->id;
> > tcon->quirks = of_device_get_match_data(dev);
> >
> > + if (tcon->quirks->needs_tcon_top) {
> > + struct device_node *np;
> > +
> > + np = of_parse_phandle(dev->of_node, "allwinner,tcon-top", 0);
> > + if (np) {
> > + struct platform_device *pdev;
> > +
> > + pdev = of_find_device_by_node(np);
> > + if (pdev)
> > + tcon->tcon_top = platform_get_drvdata(pdev);
> > + of_node_put(np);
> > +
> > + if (!tcon->tcon_top)
> > + return -EPROBE_DEFER;
> > + }
> > + }
> > +
>
> I might have missed it, but I've not seen the bindings additions for
> that property. This shouldn't really be done that way anyway, instead
> of using a direct phandle, you should be using the of-graph, with the
> TCON-top sitting where it belongs in the flow of data.

Just to answer to the first question, it did describe it in "[PATCH 07/15] dt-
bindings: display: sun4i-drm: Add R40 HDMI pipeline".

As why I designed it that way - HW representation could be described that way
(ASCII art makes sense when fixed width font is used to view it):

/ LCD0/LVDS0
/ TCON-LCD0
| \ MIPI DSI
mixer0 |
\ / TCON-LCD1 - LCD1/LVDS1
TCON-TOP
/ \ TCON-TV0 - TVE0/RGB
mixer1 | \
| TCON-TOP - HDMI
| /
\ TCON-TV1 - TVE1/RGB

This is a bit simplified, since there is also TVE-TOP, which is responsible
for sharing 4 DACs between both TVE encoders. You can have two TV outs (PAL/
NTSC) or TVE0 as TV out and TVE1 as RGB or vice versa. It even seems that you
can arbitrarly choose which DAC is responsible for which signal, so there is a
ton of possible end combinations, but I'm not 100% sure.

Even though I wrote TCON-TOP twice, this is same unit in HW. R40 manual
suggest more possibilities, although some of them seem wrong, like RGB feeding
from LCD TCON. That is confirmed to be wrong when checking BSP code.

Additionally, TCON-TOP comes in the middle of TVE0 and LCD0, TVE1 and LCD1 for
pin muxing, although I'm not sure why is that needed at all, since according
to R40 datasheet, TVE0 and TVE1 pins are dedicated and not on PORT D and PORT
H, respectively, as TCON-TOP documentation suggest. However, HSYNC and PSYNC
lines might be shared between TVE (when it works in RGB mode) and LCD. But
that is just my guess since I'm not really familiar with RGB and LCD
interfaces.

I'm really not sure what would be the best representation in OF-graph. Can you
suggest one?

On the other hand, mux callback in TCON driver has all available informations
at hand. It knows mixer ID, TCON ID and most importantly, encoder type. Based
on all that informations, it's easy to configure TCON TOP.

I hope you understand. If you have better idea, I'm all ears, since phandle
seems a bit weird to me too, but I think it's the only future proof, when
adding LVDS, RGB, TVE or LCD support.

Best regards,
Jernej



2018-05-22 02:26:43

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 05/15] drm/sun4i: Add TCON TOP driver

Hi Jernej,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on drm/drm-next]
[also build test ERROR on v4.17-rc6 next-20180517]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Jernej-Skrabec/Add-support-for-R40-HDMI-pipeline/20180521-131839
base: git://people.freedesktop.org/~airlied/linux.git drm-next
config: arm-multi_v7_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm

All errors (new ones prefixed by >>):

drivers/gpu/drm/sun4i/sun8i_tcon_top.o: In function `init_module':
>> sun8i_tcon_top.c:(.init.text+0x0): multiple definition of `init_module'
drivers/gpu/drm/sun4i/sun8i_mixer.o:sun8i_mixer.c:(.init.text+0x0): first defined here
drivers/gpu/drm/sun4i/sun8i_tcon_top.o: In function `cleanup_module':
>> sun8i_tcon_top.c:(.exit.text+0x0): multiple definition of `cleanup_module'
drivers/gpu/drm/sun4i/sun8i_mixer.o:sun8i_mixer.c:(.exit.text+0x0): first defined here

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (1.45 kB)
.config.gz (42.33 kB)
Download all attachments

2018-05-23 18:20:58

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH 03/15] clk: sunxi-ng: r40: Export video PLLs

On Sat, May 19, 2018 at 08:31:15PM +0200, Jernej Skrabec wrote:
> Video PLLs need to be referenced in R40 DT as possible HDMI PHY parent.
>
> Export them.
>
> Signed-off-by: Jernej Skrabec <[email protected]>
> ---
> drivers/clk/sunxi-ng/ccu-sun8i-r40.h | 8 ++++++--
> include/dt-bindings/clock/sun8i-r40-ccu.h | 4 ++++
> 2 files changed, 10 insertions(+), 2 deletions(-)

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

2018-05-23 18:23:46

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH 05/15] drm/sun4i: Add TCON TOP driver

On Sat, May 19, 2018 at 08:31:17PM +0200, Jernej Skrabec wrote:
> As already described in DT binding, TCON TOP is responsible for
> configuring display pipeline. In this initial driver focus is on HDMI
> pipeline, so TVE and LCD configuration is not implemented.
>
> Implemented features:
> - HDMI source selection
> - clock driver (TCON and DSI gating)
> - connecting mixers and TCONS
>
> Something similar also existed in previous SoCs, except that it was part
> of first TCON.
>
> Signed-off-by: Jernej Skrabec <[email protected]>
> ---
> drivers/gpu/drm/sun4i/Makefile | 3 +-
> drivers/gpu/drm/sun4i/sun8i_tcon_top.c | 256 +++++++++++++++++++++
> drivers/gpu/drm/sun4i/sun8i_tcon_top.h | 20 ++
> include/dt-bindings/clock/sun8i-tcon-top.h | 11 +

This belongs with the binding doc patch.

> 4 files changed, 289 insertions(+), 1 deletion(-)
> create mode 100644 drivers/gpu/drm/sun4i/sun8i_tcon_top.c
> create mode 100644 drivers/gpu/drm/sun4i/sun8i_tcon_top.h
> create mode 100644 include/dt-bindings/clock/sun8i-tcon-top.h

2018-05-24 08:28:10

by Maxime Ripard

[permalink] [raw]
Subject: Re: [linux-sunxi] Re: [PATCH 12/15] drm/sun4i: Add support for second clock parent to DW HDMI PHY clk driver

On Mon, May 21, 2018 at 05:02:23PM +0200, Jernej Škrabec wrote:
> Hi,
>
> Dne ponedeljek, 21. maj 2018 ob 10:12:53 CEST je Maxime Ripard napisal(a):
> > On Sat, May 19, 2018 at 08:31:24PM +0200, Jernej Skrabec wrote:
> > > Expand HDMI PHY clock driver to support second clock parent.
> > >
> > > Signed-off-by: Jernej Skrabec <[email protected]>
> > > ---
> > >
> > > drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 6 +-
> > > drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 29 ++++++-
> > > drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c | 90 ++++++++++++++++------
> > > 3 files changed, 98 insertions(+), 27 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
> > > b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h index 801a17222762..aadbe0a10b0c
> > > 100644
> > > --- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
> > > +++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
> > > @@ -98,7 +98,8 @@
> > >
> > > #define SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN BIT(29)
> > > #define SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN BIT(28)
> > > #define SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 BIT(27)
> > >
> > > -#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL BIT(26)
> > > +#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK BIT(26)
> > > +#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT 26
> > >
> > > #define SUN8I_HDMI_PHY_PLL_CFG1_PLLEN BIT(25)
> > > #define SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(x) ((x) << 22)
> > > #define SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(x) ((x) << 20)
> > >
> > > @@ -190,6 +191,7 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi
> > > *hdmi);
> > >
> > > void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
> > > const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void);
> > >
> > > -int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev);
> > > +int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev,
> > > + bool second_parent);
> > >
> > > #endif /* _SUN8I_DW_HDMI_H_ */
> > >
> > > diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
> > > b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index deba47ed69d8..7a911f0a3ae3
> > > 100644
> > > --- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
> > > +++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
> > > @@ -183,7 +183,13 @@ static int sun8i_hdmi_phy_config_h3(struct dw_hdmi
> > > *hdmi,>
> > > regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
> > >
> > > SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK, 0);
> > >
> > > - regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, pll_cfg1_init);
> > > + /*
> > > + * NOTE: We have to be careful not to overwrite PHY parent
> > > + * clock selection bit and clock divider.
> > > + */
> > > + regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
> > > + ~SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK,
> > > + pll_cfg1_init);
> >
> > It feels like it belongs in a separate patch.
>
> Why? clk_set_rate() on HDMI PHY clock is called before this function, so
> SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL bit is already set to correct value. Original
> code doesn't take this into account and sets it to 0 here in all cases, which
> obviously is not right.
>
> If you insist on splitting this in new patch, it has to be applied before
> clock changes. It would also need to include "reset PLL clock configuration"
> chunk (next change in this patch), otherwise other SoCs with only one parent
> could get 1 there, which is obviously wrong. Note that I didn't really tested
> if default value of this bit is 0 or 1, but I wouldn't really like to depend
> on default values.

I don't have a strong feeling about this, but to me, the fact that you
don't want to overwrite the muxing bit because the clock might use it
is sensible in itself, disregarding the fact that the clock *will* use
it.

>
> >
> > > regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG,
> > >
> > > (u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK,
> > > pll_cfg2_init);
> > >
> > > @@ -352,6 +358,10 @@ static void sun8i_hdmi_phy_init_h3(struct
> > > sun8i_hdmi_phy *phy)>
> > > SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
> > > SUN8I_HDMI_PHY_ANA_CFG3_SDAEN);
> > >
> > > + /* reset PLL clock configuration */
> > > + regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 0);
> > > + regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG, 0);
> > > +
> >
> > Ditto,
> >
> > > +
> > > + /*
> > > + * Even though HDMI PHY clock doesn't have enable/disable
> > > + * handlers, we have to enable it. Otherwise it could happen
> > > + * that parent PLL is not enabled by clock framework in a
> > > + * highly unlikely event when parent PLL is used solely for
> > > + * HDMI PHY clock.
> > > + */
> > > + clk_prepare_enable(phy->clk_phy);
> >
> > The implementation of the clock doesn't really matter in our API
> > usage. If we're using a clock, we have to call
> > clk_prepare_enable. That's documented everywhere, and mentionning how
> > the clock is implemented is an abstraction leakage and it's
> > irrelevant. I'd simply remove the comment here.
> >
> > And it should be in a separate patch as well.
>
> OK. Should I add Fixes tag, since current code obviously is not by the specs?
> It could still get in 4.17...

Yep!

Maxime

--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com


Attachments:
(No filename) (5.31 kB)
signature.asc (849.00 B)
Download all attachments

2018-05-24 08:45:10

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 05/15] drm/sun4i: Add TCON TOP driver

Hi,

On Mon, May 21, 2018 at 05:15:15PM +0200, Jernej Škrabec wrote:
> > > + /*
> > > + * Default register values might have some reserved bits set, which
> > > + * prevents TCON TOP from working properly. Set them to 0 here.
> > > + */
> > > + writel(0, tcon_top->regs + TCON_TOP_PORT_SEL_REG);
> > > + writel(0, tcon_top->regs + TCON_TOP_GATE_SRC_REG);
> > > +
> > > + for (i = 0; i < CLK_NUM; i++) {
> > > + const char *parent_name = "bus-tcon-top";
> >
> > I guess retrieving the parent's clock name at runtime would be more
> > flexible.
>
> It is, but will it ever be anything else?

Probably not, but when the complexity is exactly the same (using
__clk_get_name), we'd better use the more appropriate solution. If we
ever need to change that clock name, or to use the driver with an SoC
that wouldn't have the same clock name for whatever reason, it will
just work.

> > > + struct clk_init_data init;
> > > + struct clk_gate *gate;
> > > +
> > > + gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
> > > + if (!gate) {
> > > + ret = -ENOMEM;
> > > + goto err_disable_clock;
> > > + }
> > > +
> > > + init.name = gates[i].name;
> > > + init.ops = &clk_gate_ops;
> > > + init.flags = CLK_IS_BASIC;
> > > + init.parent_names = &parent_name;
> > > + init.num_parents = 1;
> > > +
> > > + gate->reg = tcon_top->regs + TCON_TOP_GATE_SRC_REG;
> > > + gate->bit_idx = gates[i].bit;
> > > + gate->lock = &tcon_top->reg_lock;
> > > + gate->hw.init = &init;
> > > +
> > > + ret = devm_clk_hw_register(dev, &gate->hw);
> > > + if (ret)
> > > + goto err_disable_clock;
> >
> > Isn't it what clk_hw_register_gate is doing?
>
> Almost, but not exactly. My goal was to use devm_* functions, so there is no
> need to do any special cleanup.

Is it the only difference? If so, you can just create a
devm_clk_hw_register gate.

Maxime

--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com


Attachments:
(No filename) (1.99 kB)
signature.asc (849.00 B)
Download all attachments

2018-05-24 08:51:04

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 06/15] drm/sun4i: tcon: Add support for tcon-top

On Mon, May 21, 2018 at 07:27:46PM +0200, Jernej Škrabec wrote:
> Hi,
>
> Dne ponedeljek, 21. maj 2018 ob 10:07:59 CEST je Maxime Ripard napisal(a):
> > On Sat, May 19, 2018 at 08:31:18PM +0200, Jernej Skrabec wrote:
> > > If SoC has TCON TOP unit, it has to be configured from TCON, since it
> > > has all information needed. Additionally, if it is TCON TV, it must also
> > > enable bus gate inside TCON TOP unit.
> >
> > Why?
>
> I'll explain my design decision below.
>
> >
> > > Add support for such TCONs.
> > >
> > > Signed-off-by: Jernej Skrabec <[email protected]>
> > > ---
> > >
> > > drivers/gpu/drm/sun4i/sun4i_tcon.c | 28 ++++++++++++++++++++++++++++
> > > drivers/gpu/drm/sun4i/sun4i_tcon.h | 8 ++++++++
> > > 2 files changed, 36 insertions(+)
> > >
> > > diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > > b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 08747fc3ee71..e0c562ce1c22
> > > 100644
> > > --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > > +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > > @@ -688,6 +688,16 @@ static int sun4i_tcon_init_clocks(struct device *dev,
> > >
> > > dev_err(dev, "Couldn't get the TCON bus clock\n");
> > > return PTR_ERR(tcon->clk);
> > >
> > > }
> > >
> > > +
> > > + if (tcon->quirks->needs_tcon_top && tcon->quirks->has_channel_1) {
> > > + tcon->top_clk = devm_clk_get(dev, "tcon-top");
> > > + if (IS_ERR(tcon->top_clk)) {
> > > + dev_err(dev, "Couldn't get the TCON TOP bus clock\n");
> > > + return PTR_ERR(tcon->top_clk);
> > > + }
> > > + clk_prepare_enable(tcon->top_clk);
> > > + }
> > > +
> > >
> > > clk_prepare_enable(tcon->clk);
> > >
> > > if (tcon->quirks->has_channel_0) {
> > >
> > > @@ -712,6 +722,7 @@ static int sun4i_tcon_init_clocks(struct device *dev,
> > >
> > > static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
> > > {
> > >
> > > clk_disable_unprepare(tcon->clk);
> > >
> > > + clk_disable_unprepare(tcon->top_clk);
> > >
> > > }
> > >
> > > static int sun4i_tcon_init_irq(struct device *dev,
> > >
> > > @@ -980,6 +991,23 @@ static int sun4i_tcon_bind(struct device *dev, struct
> > > device *master,>
> > > tcon->id = engine->id;
> > > tcon->quirks = of_device_get_match_data(dev);
> > >
> > > + if (tcon->quirks->needs_tcon_top) {
> > > + struct device_node *np;
> > > +
> > > + np = of_parse_phandle(dev->of_node, "allwinner,tcon-top", 0);
> > > + if (np) {
> > > + struct platform_device *pdev;
> > > +
> > > + pdev = of_find_device_by_node(np);
> > > + if (pdev)
> > > + tcon->tcon_top = platform_get_drvdata(pdev);
> > > + of_node_put(np);
> > > +
> > > + if (!tcon->tcon_top)
> > > + return -EPROBE_DEFER;
> > > + }
> > > + }
> > > +
> >
> > I might have missed it, but I've not seen the bindings additions for
> > that property. This shouldn't really be done that way anyway, instead
> > of using a direct phandle, you should be using the of-graph, with the
> > TCON-top sitting where it belongs in the flow of data.
>
> Just to answer to the first question, it did describe it in "[PATCH 07/15] dt-
> bindings: display: sun4i-drm: Add R40 HDMI pipeline".
>
> As why I designed it that way - HW representation could be described that way
> (ASCII art makes sense when fixed width font is used to view it):
>
> / LCD0/LVDS0
> / TCON-LCD0
> | \ MIPI DSI
> mixer0 |
> \ / TCON-LCD1 - LCD1/LVDS1
> TCON-TOP
> / \ TCON-TV0 - TVE0/RGB
> mixer1 | \
> | TCON-TOP - HDMI
> | /
> \ TCON-TV1 - TVE1/RGB
>
> This is a bit simplified, since there is also TVE-TOP, which is responsible
> for sharing 4 DACs between both TVE encoders. You can have two TV outs (PAL/
> NTSC) or TVE0 as TV out and TVE1 as RGB or vice versa. It even seems that you
> can arbitrarly choose which DAC is responsible for which signal, so there is a
> ton of possible end combinations, but I'm not 100% sure.
>
> Even though I wrote TCON-TOP twice, this is same unit in HW. R40 manual
> suggest more possibilities, although some of them seem wrong, like RGB feeding
> from LCD TCON. That is confirmed to be wrong when checking BSP code.
>
> Additionally, TCON-TOP comes in the middle of TVE0 and LCD0, TVE1 and LCD1 for
> pin muxing, although I'm not sure why is that needed at all, since according
> to R40 datasheet, TVE0 and TVE1 pins are dedicated and not on PORT D and PORT
> H, respectively, as TCON-TOP documentation suggest. However, HSYNC and PSYNC
> lines might be shared between TVE (when it works in RGB mode) and LCD. But
> that is just my guess since I'm not really familiar with RGB and LCD
> interfaces.
>
> I'm really not sure what would be the best representation in OF-graph. Can you
> suggest one?

Rob might disagree on this one, but I don't see anything wrong with
having loops in the graph. If the TCON-TOP can be both the input and
output of the TCONs, then so be it, and have it described that way in
the graph.

The code is already able to filter out nodes that have already been
added to the list of devices we need to wait for in the component
framework, so that should work as well.

And we'd need to describe TVE-TOP as well, even though we don't have a
driver for it yet. That will simplify the backward compatibility later
on.

Maxime

--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com


Attachments:
(No filename) (5.56 kB)
signature.asc (849.00 B)
Download all attachments

2018-05-25 02:43:31

by Jernej Skrabec

[permalink] [raw]
Subject: Re: [linux-sunxi] Re: [PATCH 05/15] drm/sun4i: Add TCON TOP driver

Hi,

Dne četrtek, 24. maj 2018 ob 10:43:51 CEST je Maxime Ripard napisal(a):
> Hi,
>
> On Mon, May 21, 2018 at 05:15:15PM +0200, Jernej Škrabec wrote:
> > > > + /*
> > > > + * Default register values might have some reserved bits set,
which
> > > > + * prevents TCON TOP from working properly. Set them to 0 here.
> > > > + */
> > > > + writel(0, tcon_top->regs + TCON_TOP_PORT_SEL_REG);
> > > > + writel(0, tcon_top->regs + TCON_TOP_GATE_SRC_REG);
> > > > +
> > > > + for (i = 0; i < CLK_NUM; i++) {
> > > > + const char *parent_name = "bus-tcon-top";
> > >
> > > I guess retrieving the parent's clock name at runtime would be more
> > > flexible.
> >
> > It is, but will it ever be anything else?
>
> Probably not, but when the complexity is exactly the same (using
> __clk_get_name), we'd better use the more appropriate solution. If we
> ever need to change that clock name, or to use the driver with an SoC
> that wouldn't have the same clock name for whatever reason, it will
> just work.
>
> > > > + struct clk_init_data init;
> > > > + struct clk_gate *gate;
> > > > +
> > > > + gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
> > > > + if (!gate) {
> > > > + ret = -ENOMEM;
> > > > + goto err_disable_clock;
> > > > + }
> > > > +
> > > > + init.name = gates[i].name;
> > > > + init.ops = &clk_gate_ops;
> > > > + init.flags = CLK_IS_BASIC;
> > > > + init.parent_names = &parent_name;
> > > > + init.num_parents = 1;
> > > > +
> > > > + gate->reg = tcon_top->regs + TCON_TOP_GATE_SRC_REG;
> > > > + gate->bit_idx = gates[i].bit;
> > > > + gate->lock = &tcon_top->reg_lock;
> > > > + gate->hw.init = &init;
> > > > +
> > > > + ret = devm_clk_hw_register(dev, &gate->hw);
> > > > + if (ret)
> > > > + goto err_disable_clock;
> > >
> > > Isn't it what clk_hw_register_gate is doing?
> >
> > Almost, but not exactly. My goal was to use devm_* functions, so there is
> > no need to do any special cleanup.
>
> Is it the only difference? If so, you can just create a
> devm_clk_hw_register gate.

I checked around and it seems that in clk core there are only non devm_*
helpers like clk_hw_register_gate() for some reason. I guess I'll just use
that and manually unregister all the clocks in cleanup function.

Best regards,
Jernej



2018-05-25 02:45:36

by Chen-Yu Tsai

[permalink] [raw]
Subject: Re: [PATCH 06/15] drm/sun4i: tcon: Add support for tcon-top

On Thu, May 24, 2018 at 1:50 AM, Maxime Ripard
<[email protected]> wrote:
> On Mon, May 21, 2018 at 07:27:46PM +0200, Jernej Škrabec wrote:
>> Hi,
>>
>> Dne ponedeljek, 21. maj 2018 ob 10:07:59 CEST je Maxime Ripard napisal(a):
>> > On Sat, May 19, 2018 at 08:31:18PM +0200, Jernej Skrabec wrote:
>> > > If SoC has TCON TOP unit, it has to be configured from TCON, since it
>> > > has all information needed. Additionally, if it is TCON TV, it must also
>> > > enable bus gate inside TCON TOP unit.
>> >
>> > Why?
>>
>> I'll explain my design decision below.
>>
>> >
>> > > Add support for such TCONs.
>> > >
>> > > Signed-off-by: Jernej Skrabec <[email protected]>
>> > > ---
>> > >
>> > > drivers/gpu/drm/sun4i/sun4i_tcon.c | 28 ++++++++++++++++++++++++++++
>> > > drivers/gpu/drm/sun4i/sun4i_tcon.h | 8 ++++++++
>> > > 2 files changed, 36 insertions(+)
>> > >
>> > > diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c
>> > > b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 08747fc3ee71..e0c562ce1c22
>> > > 100644
>> > > --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
>> > > +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
>> > > @@ -688,6 +688,16 @@ static int sun4i_tcon_init_clocks(struct device *dev,
>> > >
>> > > dev_err(dev, "Couldn't get the TCON bus clock\n");
>> > > return PTR_ERR(tcon->clk);
>> > >
>> > > }
>> > >
>> > > +
>> > > + if (tcon->quirks->needs_tcon_top && tcon->quirks->has_channel_1) {
>> > > + tcon->top_clk = devm_clk_get(dev, "tcon-top");
>> > > + if (IS_ERR(tcon->top_clk)) {
>> > > + dev_err(dev, "Couldn't get the TCON TOP bus clock\n");
>> > > + return PTR_ERR(tcon->top_clk);
>> > > + }
>> > > + clk_prepare_enable(tcon->top_clk);
>> > > + }
>> > > +
>> > >
>> > > clk_prepare_enable(tcon->clk);
>> > >
>> > > if (tcon->quirks->has_channel_0) {
>> > >
>> > > @@ -712,6 +722,7 @@ static int sun4i_tcon_init_clocks(struct device *dev,
>> > >
>> > > static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
>> > > {
>> > >
>> > > clk_disable_unprepare(tcon->clk);
>> > >
>> > > + clk_disable_unprepare(tcon->top_clk);
>> > >
>> > > }
>> > >
>> > > static int sun4i_tcon_init_irq(struct device *dev,
>> > >
>> > > @@ -980,6 +991,23 @@ static int sun4i_tcon_bind(struct device *dev, struct
>> > > device *master,>
>> > > tcon->id = engine->id;
>> > > tcon->quirks = of_device_get_match_data(dev);
>> > >
>> > > + if (tcon->quirks->needs_tcon_top) {
>> > > + struct device_node *np;
>> > > +
>> > > + np = of_parse_phandle(dev->of_node, "allwinner,tcon-top", 0);
>> > > + if (np) {
>> > > + struct platform_device *pdev;
>> > > +
>> > > + pdev = of_find_device_by_node(np);
>> > > + if (pdev)
>> > > + tcon->tcon_top = platform_get_drvdata(pdev);
>> > > + of_node_put(np);
>> > > +
>> > > + if (!tcon->tcon_top)
>> > > + return -EPROBE_DEFER;
>> > > + }
>> > > + }
>> > > +
>> >
>> > I might have missed it, but I've not seen the bindings additions for
>> > that property. This shouldn't really be done that way anyway, instead
>> > of using a direct phandle, you should be using the of-graph, with the
>> > TCON-top sitting where it belongs in the flow of data.
>>
>> Just to answer to the first question, it did describe it in "[PATCH 07/15] dt-
>> bindings: display: sun4i-drm: Add R40 HDMI pipeline".
>>
>> As why I designed it that way - HW representation could be described that way
>> (ASCII art makes sense when fixed width font is used to view it):
>>
>> / LCD0/LVDS0
>> / TCON-LCD0
>> | \ MIPI DSI
>> mixer0 |
>> \ / TCON-LCD1 - LCD1/LVDS1
>> TCON-TOP
>> / \ TCON-TV0 - TVE0/RGB
>> mixer1 | \
>> | TCON-TOP - HDMI
>> | /
>> \ TCON-TV1 - TVE1/RGB
>>
>> This is a bit simplified, since there is also TVE-TOP, which is responsible
>> for sharing 4 DACs between both TVE encoders. You can have two TV outs (PAL/
>> NTSC) or TVE0 as TV out and TVE1 as RGB or vice versa. It even seems that you
>> can arbitrarly choose which DAC is responsible for which signal, so there is a
>> ton of possible end combinations, but I'm not 100% sure.
>>
>> Even though I wrote TCON-TOP twice, this is same unit in HW. R40 manual
>> suggest more possibilities, although some of them seem wrong, like RGB feeding
>> from LCD TCON. That is confirmed to be wrong when checking BSP code.
>>
>> Additionally, TCON-TOP comes in the middle of TVE0 and LCD0, TVE1 and LCD1 for
>> pin muxing, although I'm not sure why is that needed at all, since according
>> to R40 datasheet, TVE0 and TVE1 pins are dedicated and not on PORT D and PORT
>> H, respectively, as TCON-TOP documentation suggest. However, HSYNC and PSYNC
>> lines might be shared between TVE (when it works in RGB mode) and LCD. But
>> that is just my guess since I'm not really familiar with RGB and LCD
>> interfaces.
>>
>> I'm really not sure what would be the best representation in OF-graph. Can you
>> suggest one?
>
> Rob might disagree on this one, but I don't see anything wrong with
> having loops in the graph. If the TCON-TOP can be both the input and
> output of the TCONs, then so be it, and have it described that way in
> the graph.
>
> The code is already able to filter out nodes that have already been
> added to the list of devices we need to wait for in the component
> framework, so that should work as well.
>
> And we'd need to describe TVE-TOP as well, even though we don't have a
> driver for it yet. That will simplify the backward compatibility later
> on.

I'm getting the feeling that TCON-TOP / TVE-TOP is the glue layer that
binds everything together, and provides signal routing, kind of like
DE-TOP on A64. So the signal mux controls that were originally found
in TCON0 and TVE0 were moved out.

The driver needs to know about that, but the graph about doesn't make
much sense directly. Without looking at the manual, I understand it to
likely be one mux between the mixers and TCONs, and one between the
TCON-TVs and HDMI. Would it make more sense to just have the graph
connections between the muxed components, and remove TCON-TOP from
it, like we had in the past? A phandle could be used to reference
the TCON-TOP for mux controls, in addition to the clocks and resets.

For TVE, we would need something to represent each of the output pins,
so the device tree can actually describe what kind of signal, be it
each component of RGB/YUV or composite video, is wanted on each pin,
if any. This is also needed on the A20 for the Cubietruck, so we can
describe which pins are tied to the VGA connector, and which one does
R, G, or B.


Regards
ChenYu

2018-05-31 09:22:46

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 06/15] drm/sun4i: tcon: Add support for tcon-top

On Thu, May 24, 2018 at 03:01:09PM -0700, Chen-Yu Tsai wrote:
> >> > > + if (tcon->quirks->needs_tcon_top) {
> >> > > + struct device_node *np;
> >> > > +
> >> > > + np = of_parse_phandle(dev->of_node, "allwinner,tcon-top", 0);
> >> > > + if (np) {
> >> > > + struct platform_device *pdev;
> >> > > +
> >> > > + pdev = of_find_device_by_node(np);
> >> > > + if (pdev)
> >> > > + tcon->tcon_top = platform_get_drvdata(pdev);
> >> > > + of_node_put(np);
> >> > > +
> >> > > + if (!tcon->tcon_top)
> >> > > + return -EPROBE_DEFER;
> >> > > + }
> >> > > + }
> >> > > +
> >> >
> >> > I might have missed it, but I've not seen the bindings additions for
> >> > that property. This shouldn't really be done that way anyway, instead
> >> > of using a direct phandle, you should be using the of-graph, with the
> >> > TCON-top sitting where it belongs in the flow of data.
> >>
> >> Just to answer to the first question, it did describe it in "[PATCH 07/15] dt-
> >> bindings: display: sun4i-drm: Add R40 HDMI pipeline".
> >>
> >> As why I designed it that way - HW representation could be described that way
> >> (ASCII art makes sense when fixed width font is used to view it):
> >>
> >> / LCD0/LVDS0
> >> / TCON-LCD0
> >> | \ MIPI DSI
> >> mixer0 |
> >> \ / TCON-LCD1 - LCD1/LVDS1
> >> TCON-TOP
> >> / \ TCON-TV0 - TVE0/RGB
> >> mixer1 | \
> >> | TCON-TOP - HDMI
> >> | /
> >> \ TCON-TV1 - TVE1/RGB
> >>
> >> This is a bit simplified, since there is also TVE-TOP, which is responsible
> >> for sharing 4 DACs between both TVE encoders. You can have two TV outs (PAL/
> >> NTSC) or TVE0 as TV out and TVE1 as RGB or vice versa. It even seems that you
> >> can arbitrarly choose which DAC is responsible for which signal, so there is a
> >> ton of possible end combinations, but I'm not 100% sure.
> >>
> >> Even though I wrote TCON-TOP twice, this is same unit in HW. R40 manual
> >> suggest more possibilities, although some of them seem wrong, like RGB feeding
> >> from LCD TCON. That is confirmed to be wrong when checking BSP code.
> >>
> >> Additionally, TCON-TOP comes in the middle of TVE0 and LCD0, TVE1 and LCD1 for
> >> pin muxing, although I'm not sure why is that needed at all, since according
> >> to R40 datasheet, TVE0 and TVE1 pins are dedicated and not on PORT D and PORT
> >> H, respectively, as TCON-TOP documentation suggest. However, HSYNC and PSYNC
> >> lines might be shared between TVE (when it works in RGB mode) and LCD. But
> >> that is just my guess since I'm not really familiar with RGB and LCD
> >> interfaces.
> >>
> >> I'm really not sure what would be the best representation in OF-graph. Can you
> >> suggest one?
> >
> > Rob might disagree on this one, but I don't see anything wrong with
> > having loops in the graph. If the TCON-TOP can be both the input and
> > output of the TCONs, then so be it, and have it described that way in
> > the graph.
> >
> > The code is already able to filter out nodes that have already been
> > added to the list of devices we need to wait for in the component
> > framework, so that should work as well.
> >
> > And we'd need to describe TVE-TOP as well, even though we don't have a
> > driver for it yet. That will simplify the backward compatibility later
> > on.
>
> I'm getting the feeling that TCON-TOP / TVE-TOP is the glue layer that
> binds everything together, and provides signal routing, kind of like
> DE-TOP on A64. So the signal mux controls that were originally found
> in TCON0 and TVE0 were moved out.
>
> The driver needs to know about that, but the graph about doesn't make
> much sense directly. Without looking at the manual, I understand it to
> likely be one mux between the mixers and TCONs, and one between the
> TCON-TVs and HDMI. Would it make more sense to just have the graph
> connections between the muxed components, and remove TCON-TOP from
> it, like we had in the past? A phandle could be used to reference
> the TCON-TOP for mux controls, in addition to the clocks and resets.
>
> For TVE, we would need something to represent each of the output pins,
> so the device tree can actually describe what kind of signal, be it
> each component of RGB/YUV or composite video, is wanted on each pin,
> if any. This is also needed on the A20 for the Cubietruck, so we can
> describe which pins are tied to the VGA connector, and which one does
> R, G, or B.

I guess we'll see how the DT maintainers feel about this, but my
impression is that the OF graph should model the flow of data between
the devices. If there's a mux somewhere, then the data is definitely
going through it, and as such it should be part of the graph.

Maxime

--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com


Attachments:
(No filename) (5.09 kB)
signature.asc (849.00 B)
Download all attachments

2018-05-31 17:56:49

by Jernej Skrabec

[permalink] [raw]
Subject: Re: [PATCH 06/15] drm/sun4i: tcon: Add support for tcon-top

Dne četrtek, 31. maj 2018 ob 11:21:33 CEST je Maxime Ripard napisal(a):
> On Thu, May 24, 2018 at 03:01:09PM -0700, Chen-Yu Tsai wrote:
> > >> > > + if (tcon->quirks->needs_tcon_top) {
> > >> > > + struct device_node *np;
> > >> > > +
> > >> > > + np = of_parse_phandle(dev->of_node, "allwinner,tcon-top",
> > >> > > 0);
> > >> > > + if (np) {
> > >> > > + struct platform_device *pdev;
> > >> > > +
> > >> > > + pdev = of_find_device_by_node(np);
> > >> > > + if (pdev)
> > >> > > + tcon->tcon_top =
> > >> > > platform_get_drvdata(pdev);
> > >> > > + of_node_put(np);
> > >> > > +
> > >> > > + if (!tcon->tcon_top)
> > >> > > + return -EPROBE_DEFER;
> > >> > > + }
> > >> > > + }
> > >> > > +
> > >> >
> > >> > I might have missed it, but I've not seen the bindings additions for
> > >> > that property. This shouldn't really be done that way anyway, instead
> > >> > of using a direct phandle, you should be using the of-graph, with the
> > >> > TCON-top sitting where it belongs in the flow of data.
> > >>
> > >> Just to answer to the first question, it did describe it in "[PATCH
> > >> 07/15] dt- bindings: display: sun4i-drm: Add R40 HDMI pipeline".
> > >>
> > >> As why I designed it that way - HW representation could be described
> > >> that way> >>
> > >> (ASCII art makes sense when fixed width font is used to view it):
> > >> / LCD0/LVDS0
> > >>
> > >> / TCON-LCD0
> > >>
> > >> | \ MIPI DSI
> > >>
> > >> mixer0 |
> > >>
> > >> \ / TCON-LCD1 - LCD1/LVDS1
> > >>
> > >> TCON-TOP
> > >>
> > >> / \ TCON-TV0 - TVE0/RGB
> > >>
> > >> mixer1 | \
> > >>
> > >> | TCON-TOP - HDMI
> > >> |
> > >> | /
> > >>
> > >> \ TCON-TV1 - TVE1/RGB
> > >>
> > >> This is a bit simplified, since there is also TVE-TOP, which is
> > >> responsible
> > >> for sharing 4 DACs between both TVE encoders. You can have two TV outs
> > >> (PAL/ NTSC) or TVE0 as TV out and TVE1 as RGB or vice versa. It even
> > >> seems that you can arbitrarly choose which DAC is responsible for
> > >> which signal, so there is a ton of possible end combinations, but I'm
> > >> not 100% sure.
> > >>
> > >> Even though I wrote TCON-TOP twice, this is same unit in HW. R40 manual
> > >> suggest more possibilities, although some of them seem wrong, like RGB
> > >> feeding from LCD TCON. That is confirmed to be wrong when checking BSP
> > >> code.
> > >>
> > >> Additionally, TCON-TOP comes in the middle of TVE0 and LCD0, TVE1 and
> > >> LCD1 for pin muxing, although I'm not sure why is that needed at all,
> > >> since according to R40 datasheet, TVE0 and TVE1 pins are dedicated and
> > >> not on PORT D and PORT H, respectively, as TCON-TOP documentation
> > >> suggest. However, HSYNC and PSYNC lines might be shared between TVE
> > >> (when it works in RGB mode) and LCD. But that is just my guess since
> > >> I'm not really familiar with RGB and LCD interfaces.
> > >>
> > >> I'm really not sure what would be the best representation in OF-graph.
> > >> Can you suggest one?
> > >
> > > Rob might disagree on this one, but I don't see anything wrong with
> > > having loops in the graph. If the TCON-TOP can be both the input and
> > > output of the TCONs, then so be it, and have it described that way in
> > > the graph.
> > >
> > > The code is already able to filter out nodes that have already been
> > > added to the list of devices we need to wait for in the component
> > > framework, so that should work as well.
> > >
> > > And we'd need to describe TVE-TOP as well, even though we don't have a
> > > driver for it yet. That will simplify the backward compatibility later
> > > on.
> >
> > I'm getting the feeling that TCON-TOP / TVE-TOP is the glue layer that
> > binds everything together, and provides signal routing, kind of like
> > DE-TOP on A64. So the signal mux controls that were originally found
> > in TCON0 and TVE0 were moved out.
> >
> > The driver needs to know about that, but the graph about doesn't make
> > much sense directly. Without looking at the manual, I understand it to
> > likely be one mux between the mixers and TCONs, and one between the
> > TCON-TVs and HDMI. Would it make more sense to just have the graph
> > connections between the muxed components, and remove TCON-TOP from
> > it, like we had in the past? A phandle could be used to reference
> > the TCON-TOP for mux controls, in addition to the clocks and resets.
> >
> > For TVE, we would need something to represent each of the output pins,
> > so the device tree can actually describe what kind of signal, be it
> > each component of RGB/YUV or composite video, is wanted on each pin,
> > if any. This is also needed on the A20 for the Cubietruck, so we can
> > describe which pins are tied to the VGA connector, and which one does
> > R, G, or B.
>
> I guess we'll see how the DT maintainers feel about this, but my
> impression is that the OF graph should model the flow of data between
> the devices. If there's a mux somewhere, then the data is definitely
> going through it, and as such it should be part of the graph.

I concur, but I spent few days thinking how to represent this sanely in graph,
but I didn't find any good solution. I'll represent here my idea and please
tell your opinion before I start implementing it.

First, let me be clear that mixer0 and mixer1 don't have same capabilities
(different number of planes, mixer0 supports writeback, mixer1 does not,
etc.). Thus, it does matter which mixer is connected to which TCON/encoder.
mixer0 is meant to be connected to main display and mixer1 to auxiliary. That
obviously depends on end system.

So, TCON TOP has 3 muxes, which have to be represented in graph. Two of them
are for mixer/TCON relationship (each of them 1 input and 4 possible outputs)
and one for TV TCON/HDMI pair selection (2 possible inputs, 1 output).

According to current practice in sun4i-drm driver, graph has to have port 0,
representing input and port 1, representing output. This would mean that graph
looks something like that:

tcon_top: tcon-top@1c70000 {
compatible = "allwinner,sun8i-r40-tcon-top";
...
ports {
#address-cells = <1>;
#size-cells = <0>;

tcon_top_in: port@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;

tcon_top_in_mixer0: endpoint@0 {
reg = <0>;
remote-endpoint = <&mixer0_out_tcon_top>;
};

tcon_top_in_mixer1: endpoint@1 {
reg = <1>;
remote-endpoint = <&mixer1_out_tcon_top>;
};

tcon_top_in_tcon_tv: endpoint@2 {
reg = <2>;
// here is HDMI input connection, part of board DTS
remote-endpoint = <board specific phandle to TV TCON output>;
};
};

tcon_top_out: port@1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;

tcon_top_out_tcon0: endpoint@0 {
reg = <0>;
// here is mixer0 output connection, part of board DTS
remote-endpoint = <board specific phandle to TCON>;
};

tcon_top_out_tcon1: endpoint@1 {
reg = <1>;
// here is mixer1 output connection, part of board DTS
remote-endpoint = <board specific phandle to TCON>;
};

tcon_top_out_hdmi: endpoint@2 {
reg = <2>;
remote-endpoint = <&hdmi_in_tcon_top>;
};
};
};
};

tcon_tv0: lcd-controller@1c73000 {
compatible = "allwinner,sun8i-r40-tcon-tv-0";
...
ports {
#address-cells = <1>;
#size-cells = <0>;

tcon_tv0_in: port@0 {
reg = <0>;

tcon_tv0_in_tcon_top: endpoint {
// endpoint depends on board, part of board DTS
remote-endpoint = <phandle to one of tcon_top_out_tcon>;
};
};

tcon_tv0_out: port@1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;

// endpoints to TV TOP and TCON TOP HDMI input
...
};
};
};

tcon_tv1: lcd-controller@1c74000 {
compatible = "allwinner,sun8i-r40-tcon-tv-1";
...
ports {
#address-cells = <1>;
#size-cells = <0>;

tcon_tv1_in: port@0 {
reg = <0>;

tcon_tv1_in_tcon_top: endpoint {
// endpoint depends on board, part of board DTS
remote-endpoint = <phandle to one of tcon_top_out_tcon>;
};
};

tcon_tv1_out: port@1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;

// endpoints to TV TOP and TCON TOP HDMI input
...
};
};
};

tcon_lcd0 and tcon_lcd1 would have similar connections, except that for
outputs would be LCD or LVDS panels or MIPI DSI encoder.

Please note that each TCON (there are 4 of them) would need to have unique
compatible and have HW index stored in quirks data. It would be used by TCON
TOP driver for configuring muxes.

What do you think about above suggestion?

Best regards,
Jernej




2018-06-01 15:32:28

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 06/15] drm/sun4i: tcon: Add support for tcon-top

On Thu, May 31, 2018 at 07:54:08PM +0200, Jernej Škrabec wrote:
> Dne četrtek, 31. maj 2018 ob 11:21:33 CEST je Maxime Ripard napisal(a):
> > On Thu, May 24, 2018 at 03:01:09PM -0700, Chen-Yu Tsai wrote:
> > > >> > > + if (tcon->quirks->needs_tcon_top) {
> > > >> > > + struct device_node *np;
> > > >> > > +
> > > >> > > + np = of_parse_phandle(dev->of_node, "allwinner,tcon-top",
> > > >> > > 0);
> > > >> > > + if (np) {
> > > >> > > + struct platform_device *pdev;
> > > >> > > +
> > > >> > > + pdev = of_find_device_by_node(np);
> > > >> > > + if (pdev)
> > > >> > > + tcon->tcon_top =
> > > >> > > platform_get_drvdata(pdev);
> > > >> > > + of_node_put(np);
> > > >> > > +
> > > >> > > + if (!tcon->tcon_top)
> > > >> > > + return -EPROBE_DEFER;
> > > >> > > + }
> > > >> > > + }
> > > >> > > +
> > > >> >
> > > >> > I might have missed it, but I've not seen the bindings additions for
> > > >> > that property. This shouldn't really be done that way anyway, instead
> > > >> > of using a direct phandle, you should be using the of-graph, with the
> > > >> > TCON-top sitting where it belongs in the flow of data.
> > > >>
> > > >> Just to answer to the first question, it did describe it in "[PATCH
> > > >> 07/15] dt- bindings: display: sun4i-drm: Add R40 HDMI pipeline".
> > > >>
> > > >> As why I designed it that way - HW representation could be described
> > > >> that way> >>
> > > >> (ASCII art makes sense when fixed width font is used to view it):
> > > >> / LCD0/LVDS0
> > > >>
> > > >> / TCON-LCD0
> > > >>
> > > >> | \ MIPI DSI
> > > >>
> > > >> mixer0 |
> > > >>
> > > >> \ / TCON-LCD1 - LCD1/LVDS1
> > > >>
> > > >> TCON-TOP
> > > >>
> > > >> / \ TCON-TV0 - TVE0/RGB
> > > >>
> > > >> mixer1 | \
> > > >>
> > > >> | TCON-TOP - HDMI
> > > >> |
> > > >> | /
> > > >>
> > > >> \ TCON-TV1 - TVE1/RGB
> > > >>
> > > >> This is a bit simplified, since there is also TVE-TOP, which is
> > > >> responsible
> > > >> for sharing 4 DACs between both TVE encoders. You can have two TV outs
> > > >> (PAL/ NTSC) or TVE0 as TV out and TVE1 as RGB or vice versa. It even
> > > >> seems that you can arbitrarly choose which DAC is responsible for
> > > >> which signal, so there is a ton of possible end combinations, but I'm
> > > >> not 100% sure.
> > > >>
> > > >> Even though I wrote TCON-TOP twice, this is same unit in HW. R40 manual
> > > >> suggest more possibilities, although some of them seem wrong, like RGB
> > > >> feeding from LCD TCON. That is confirmed to be wrong when checking BSP
> > > >> code.
> > > >>
> > > >> Additionally, TCON-TOP comes in the middle of TVE0 and LCD0, TVE1 and
> > > >> LCD1 for pin muxing, although I'm not sure why is that needed at all,
> > > >> since according to R40 datasheet, TVE0 and TVE1 pins are dedicated and
> > > >> not on PORT D and PORT H, respectively, as TCON-TOP documentation
> > > >> suggest. However, HSYNC and PSYNC lines might be shared between TVE
> > > >> (when it works in RGB mode) and LCD. But that is just my guess since
> > > >> I'm not really familiar with RGB and LCD interfaces.
> > > >>
> > > >> I'm really not sure what would be the best representation in OF-graph.
> > > >> Can you suggest one?
> > > >
> > > > Rob might disagree on this one, but I don't see anything wrong with
> > > > having loops in the graph. If the TCON-TOP can be both the input and
> > > > output of the TCONs, then so be it, and have it described that way in
> > > > the graph.
> > > >
> > > > The code is already able to filter out nodes that have already been
> > > > added to the list of devices we need to wait for in the component
> > > > framework, so that should work as well.
> > > >
> > > > And we'd need to describe TVE-TOP as well, even though we don't have a
> > > > driver for it yet. That will simplify the backward compatibility later
> > > > on.
> > >
> > > I'm getting the feeling that TCON-TOP / TVE-TOP is the glue layer that
> > > binds everything together, and provides signal routing, kind of like
> > > DE-TOP on A64. So the signal mux controls that were originally found
> > > in TCON0 and TVE0 were moved out.
> > >
> > > The driver needs to know about that, but the graph about doesn't make
> > > much sense directly. Without looking at the manual, I understand it to
> > > likely be one mux between the mixers and TCONs, and one between the
> > > TCON-TVs and HDMI. Would it make more sense to just have the graph
> > > connections between the muxed components, and remove TCON-TOP from
> > > it, like we had in the past? A phandle could be used to reference
> > > the TCON-TOP for mux controls, in addition to the clocks and resets.
> > >
> > > For TVE, we would need something to represent each of the output pins,
> > > so the device tree can actually describe what kind of signal, be it
> > > each component of RGB/YUV or composite video, is wanted on each pin,
> > > if any. This is also needed on the A20 for the Cubietruck, so we can
> > > describe which pins are tied to the VGA connector, and which one does
> > > R, G, or B.
> >
> > I guess we'll see how the DT maintainers feel about this, but my
> > impression is that the OF graph should model the flow of data between
> > the devices. If there's a mux somewhere, then the data is definitely
> > going through it, and as such it should be part of the graph.
>
> I concur, but I spent few days thinking how to represent this sanely in graph,
> but I didn't find any good solution. I'll represent here my idea and please
> tell your opinion before I start implementing it.
>
> First, let me be clear that mixer0 and mixer1 don't have same capabilities
> (different number of planes, mixer0 supports writeback, mixer1 does not,
> etc.). Thus, it does matter which mixer is connected to which TCON/encoder.
> mixer0 is meant to be connected to main display and mixer1 to auxiliary. That
> obviously depends on end system.
>
> So, TCON TOP has 3 muxes, which have to be represented in graph. Two of them
> are for mixer/TCON relationship (each of them 1 input and 4 possible outputs)
> and one for TV TCON/HDMI pair selection (2 possible inputs, 1 output).
>
> According to current practice in sun4i-drm driver, graph has to have port 0,
> representing input and port 1, representing output. This would mean that graph
> looks something like that:
>
> tcon_top: tcon-top@1c70000 {
> compatible = "allwinner,sun8i-r40-tcon-top";
> ...
> ports {
> #address-cells = <1>;
> #size-cells = <0>;
>
> tcon_top_in: port@0 {
> #address-cells = <1>;
> #size-cells = <0>;
> reg = <0>;
>
> tcon_top_in_mixer0: endpoint@0 {
> reg = <0>;
> remote-endpoint = <&mixer0_out_tcon_top>;
> };
>
> tcon_top_in_mixer1: endpoint@1 {
> reg = <1>;
> remote-endpoint = <&mixer1_out_tcon_top>;
> };
>
> tcon_top_in_tcon_tv: endpoint@2 {
> reg = <2>;
> // here is HDMI input connection, part of board DTS
> remote-endpoint = <board specific phandle to TV TCON output>;
> };
> };
>
> tcon_top_out: port@1 {
> #address-cells = <1>;
> #size-cells = <0>;
> reg = <1>;
>
> tcon_top_out_tcon0: endpoint@0 {
> reg = <0>;
> // here is mixer0 output connection, part of board DTS
> remote-endpoint = <board specific phandle to TCON>;
> };
>
> tcon_top_out_tcon1: endpoint@1 {
> reg = <1>;
> // here is mixer1 output connection, part of board DTS
> remote-endpoint = <board specific phandle to TCON>;
> };
>
> tcon_top_out_hdmi: endpoint@2 {
> reg = <2>;
> remote-endpoint = <&hdmi_in_tcon_top>;
> };
> };
> };
> };

IIRC, each port is supposed to be one route for the data, so we would
have multiple ports, one for the mixers in input and for the tcon in
output, and one for the TCON in input and for the HDMI/TV in
output. Rob might correct me here.

> tcon_tv0: lcd-controller@1c73000 {
> compatible = "allwinner,sun8i-r40-tcon-tv-0";
> ...
> ports {
> #address-cells = <1>;
> #size-cells = <0>;
>
> tcon_tv0_in: port@0 {
> reg = <0>;
>
> tcon_tv0_in_tcon_top: endpoint {
> // endpoint depends on board, part of board DTS
> remote-endpoint = <phandle to one of tcon_top_out_tcon>;

Just curious, what would be there?

> };
> };
>
> tcon_tv0_out: port@1 {
> #address-cells = <1>;
> #size-cells = <0>;
> reg = <1>;
>
> // endpoints to TV TOP and TCON TOP HDMI input
> ...
> };
> };
> };
>
> tcon_tv1: lcd-controller@1c74000 {
> compatible = "allwinner,sun8i-r40-tcon-tv-1";
> ...
> ports {
> #address-cells = <1>;
> #size-cells = <0>;
>
> tcon_tv1_in: port@0 {
> reg = <0>;
>
> tcon_tv1_in_tcon_top: endpoint {
> // endpoint depends on board, part of board DTS
> remote-endpoint = <phandle to one of tcon_top_out_tcon>;
> };
> };
>
> tcon_tv1_out: port@1 {
> #address-cells = <1>;
> #size-cells = <0>;
> reg = <1>;
>
> // endpoints to TV TOP and TCON TOP HDMI input
> ...
> };
> };
> };
>
> tcon_lcd0 and tcon_lcd1 would have similar connections, except that for
> outputs would be LCD or LVDS panels or MIPI DSI encoder.
>
> Please note that each TCON (there are 4 of them) would need to have unique
> compatible and have HW index stored in quirks data. It would be used by TCON
> TOP driver for configuring muxes.

Can't we use the port/endpoint ID instead? If the mux is the only
thing that changes, the compatible has no reason to. It's the same IP,
and the only thing that changes is something that is not part of that
IP.

Maxime

--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com


Attachments:
(No filename) (10.12 kB)
signature.asc (849.00 B)
Download all attachments

2018-06-01 16:20:53

by Chen-Yu Tsai

[permalink] [raw]
Subject: Re: [PATCH 06/15] drm/sun4i: tcon: Add support for tcon-top

On Fri, Jun 1, 2018 at 8:29 AM, Maxime Ripard <[email protected]> wrote:
> On Thu, May 31, 2018 at 07:54:08PM +0200, Jernej Škrabec wrote:
>> Dne četrtek, 31. maj 2018 ob 11:21:33 CEST je Maxime Ripard napisal(a):
>> > On Thu, May 24, 2018 at 03:01:09PM -0700, Chen-Yu Tsai wrote:
>> > > >> > > + if (tcon->quirks->needs_tcon_top) {
>> > > >> > > + struct device_node *np;
>> > > >> > > +
>> > > >> > > + np = of_parse_phandle(dev->of_node, "allwinner,tcon-top",
>> > > >> > > 0);
>> > > >> > > + if (np) {
>> > > >> > > + struct platform_device *pdev;
>> > > >> > > +
>> > > >> > > + pdev = of_find_device_by_node(np);
>> > > >> > > + if (pdev)
>> > > >> > > + tcon->tcon_top =
>> > > >> > > platform_get_drvdata(pdev);
>> > > >> > > + of_node_put(np);
>> > > >> > > +
>> > > >> > > + if (!tcon->tcon_top)
>> > > >> > > + return -EPROBE_DEFER;
>> > > >> > > + }
>> > > >> > > + }
>> > > >> > > +
>> > > >> >
>> > > >> > I might have missed it, but I've not seen the bindings additions for
>> > > >> > that property. This shouldn't really be done that way anyway, instead
>> > > >> > of using a direct phandle, you should be using the of-graph, with the
>> > > >> > TCON-top sitting where it belongs in the flow of data.
>> > > >>
>> > > >> Just to answer to the first question, it did describe it in "[PATCH
>> > > >> 07/15] dt- bindings: display: sun4i-drm: Add R40 HDMI pipeline".
>> > > >>
>> > > >> As why I designed it that way - HW representation could be described
>> > > >> that way> >>
>> > > >> (ASCII art makes sense when fixed width font is used to view it):
>> > > >> / LCD0/LVDS0
>> > > >>
>> > > >> / TCON-LCD0
>> > > >>
>> > > >> | \ MIPI DSI
>> > > >>
>> > > >> mixer0 |
>> > > >>
>> > > >> \ / TCON-LCD1 - LCD1/LVDS1
>> > > >>
>> > > >> TCON-TOP
>> > > >>
>> > > >> / \ TCON-TV0 - TVE0/RGB
>> > > >>
>> > > >> mixer1 | \
>> > > >>
>> > > >> | TCON-TOP - HDMI
>> > > >> |
>> > > >> | /
>> > > >>
>> > > >> \ TCON-TV1 - TVE1/RGB
>> > > >>
>> > > >> This is a bit simplified, since there is also TVE-TOP, which is
>> > > >> responsible
>> > > >> for sharing 4 DACs between both TVE encoders. You can have two TV outs
>> > > >> (PAL/ NTSC) or TVE0 as TV out and TVE1 as RGB or vice versa. It even
>> > > >> seems that you can arbitrarly choose which DAC is responsible for
>> > > >> which signal, so there is a ton of possible end combinations, but I'm
>> > > >> not 100% sure.
>> > > >>
>> > > >> Even though I wrote TCON-TOP twice, this is same unit in HW. R40 manual
>> > > >> suggest more possibilities, although some of them seem wrong, like RGB
>> > > >> feeding from LCD TCON. That is confirmed to be wrong when checking BSP
>> > > >> code.
>> > > >>
>> > > >> Additionally, TCON-TOP comes in the middle of TVE0 and LCD0, TVE1 and
>> > > >> LCD1 for pin muxing, although I'm not sure why is that needed at all,
>> > > >> since according to R40 datasheet, TVE0 and TVE1 pins are dedicated and
>> > > >> not on PORT D and PORT H, respectively, as TCON-TOP documentation
>> > > >> suggest. However, HSYNC and PSYNC lines might be shared between TVE
>> > > >> (when it works in RGB mode) and LCD. But that is just my guess since
>> > > >> I'm not really familiar with RGB and LCD interfaces.
>> > > >>
>> > > >> I'm really not sure what would be the best representation in OF-graph.
>> > > >> Can you suggest one?
>> > > >
>> > > > Rob might disagree on this one, but I don't see anything wrong with
>> > > > having loops in the graph. If the TCON-TOP can be both the input and
>> > > > output of the TCONs, then so be it, and have it described that way in
>> > > > the graph.
>> > > >
>> > > > The code is already able to filter out nodes that have already been
>> > > > added to the list of devices we need to wait for in the component
>> > > > framework, so that should work as well.
>> > > >
>> > > > And we'd need to describe TVE-TOP as well, even though we don't have a
>> > > > driver for it yet. That will simplify the backward compatibility later
>> > > > on.
>> > >
>> > > I'm getting the feeling that TCON-TOP / TVE-TOP is the glue layer that
>> > > binds everything together, and provides signal routing, kind of like
>> > > DE-TOP on A64. So the signal mux controls that were originally found
>> > > in TCON0 and TVE0 were moved out.
>> > >
>> > > The driver needs to know about that, but the graph about doesn't make
>> > > much sense directly. Without looking at the manual, I understand it to
>> > > likely be one mux between the mixers and TCONs, and one between the
>> > > TCON-TVs and HDMI. Would it make more sense to just have the graph
>> > > connections between the muxed components, and remove TCON-TOP from
>> > > it, like we had in the past? A phandle could be used to reference
>> > > the TCON-TOP for mux controls, in addition to the clocks and resets.
>> > >
>> > > For TVE, we would need something to represent each of the output pins,
>> > > so the device tree can actually describe what kind of signal, be it
>> > > each component of RGB/YUV or composite video, is wanted on each pin,
>> > > if any. This is also needed on the A20 for the Cubietruck, so we can
>> > > describe which pins are tied to the VGA connector, and which one does
>> > > R, G, or B.
>> >
>> > I guess we'll see how the DT maintainers feel about this, but my
>> > impression is that the OF graph should model the flow of data between
>> > the devices. If there's a mux somewhere, then the data is definitely
>> > going through it, and as such it should be part of the graph.
>>
>> I concur, but I spent few days thinking how to represent this sanely in graph,
>> but I didn't find any good solution. I'll represent here my idea and please
>> tell your opinion before I start implementing it.
>>
>> First, let me be clear that mixer0 and mixer1 don't have same capabilities
>> (different number of planes, mixer0 supports writeback, mixer1 does not,
>> etc.). Thus, it does matter which mixer is connected to which TCON/encoder.
>> mixer0 is meant to be connected to main display and mixer1 to auxiliary. That
>> obviously depends on end system.
>>
>> So, TCON TOP has 3 muxes, which have to be represented in graph. Two of them
>> are for mixer/TCON relationship (each of them 1 input and 4 possible outputs)
>> and one for TV TCON/HDMI pair selection (2 possible inputs, 1 output).
>>
>> According to current practice in sun4i-drm driver, graph has to have port 0,
>> representing input and port 1, representing output. This would mean that graph
>> looks something like that:
>>
>> tcon_top: tcon-top@1c70000 {
>> compatible = "allwinner,sun8i-r40-tcon-top";
>> ...
>> ports {
>> #address-cells = <1>;
>> #size-cells = <0>;
>>
>> tcon_top_in: port@0 {
>> #address-cells = <1>;
>> #size-cells = <0>;
>> reg = <0>;
>>
>> tcon_top_in_mixer0: endpoint@0 {
>> reg = <0>;
>> remote-endpoint = <&mixer0_out_tcon_top>;
>> };
>>
>> tcon_top_in_mixer1: endpoint@1 {
>> reg = <1>;
>> remote-endpoint = <&mixer1_out_tcon_top>;
>> };
>>
>> tcon_top_in_tcon_tv: endpoint@2 {
>> reg = <2>;
>> // here is HDMI input connection, part of board DTS
>> remote-endpoint = <board specific phandle to TV TCON output>;
>> };
>> };
>>
>> tcon_top_out: port@1 {
>> #address-cells = <1>;
>> #size-cells = <0>;
>> reg = <1>;
>>
>> tcon_top_out_tcon0: endpoint@0 {
>> reg = <0>;
>> // here is mixer0 output connection, part of board DTS
>> remote-endpoint = <board specific phandle to TCON>;
>> };
>>
>> tcon_top_out_tcon1: endpoint@1 {
>> reg = <1>;
>> // here is mixer1 output connection, part of board DTS
>> remote-endpoint = <board specific phandle to TCON>;
>> };
>>
>> tcon_top_out_hdmi: endpoint@2 {
>> reg = <2>;
>> remote-endpoint = <&hdmi_in_tcon_top>;
>> };
>> };
>> };
>> };
>
> IIRC, each port is supposed to be one route for the data, so we would
> have multiple ports, one for the mixers in input and for the tcon in
> output, and one for the TCON in input and for the HDMI/TV in
> output. Rob might correct me here.
>
>> tcon_tv0: lcd-controller@1c73000 {
>> compatible = "allwinner,sun8i-r40-tcon-tv-0";
>> ...
>> ports {
>> #address-cells = <1>;
>> #size-cells = <0>;
>>
>> tcon_tv0_in: port@0 {
>> reg = <0>;
>>
>> tcon_tv0_in_tcon_top: endpoint {
>> // endpoint depends on board, part of board DTS
>> remote-endpoint = <phandle to one of tcon_top_out_tcon>;
>
> Just curious, what would be there?
>
>> };
>> };
>>
>> tcon_tv0_out: port@1 {
>> #address-cells = <1>;
>> #size-cells = <0>;
>> reg = <1>;
>>
>> // endpoints to TV TOP and TCON TOP HDMI input
>> ...
>> };
>> };
>> };
>>
>> tcon_tv1: lcd-controller@1c74000 {
>> compatible = "allwinner,sun8i-r40-tcon-tv-1";
>> ...
>> ports {
>> #address-cells = <1>;
>> #size-cells = <0>;
>>
>> tcon_tv1_in: port@0 {
>> reg = <0>;
>>
>> tcon_tv1_in_tcon_top: endpoint {
>> // endpoint depends on board, part of board DTS
>> remote-endpoint = <phandle to one of tcon_top_out_tcon>;
>> };
>> };
>>
>> tcon_tv1_out: port@1 {
>> #address-cells = <1>;
>> #size-cells = <0>;
>> reg = <1>;
>>
>> // endpoints to TV TOP and TCON TOP HDMI input
>> ...
>> };
>> };
>> };
>>
>> tcon_lcd0 and tcon_lcd1 would have similar connections, except that for
>> outputs would be LCD or LVDS panels or MIPI DSI encoder.
>>
>> Please note that each TCON (there are 4 of them) would need to have unique
>> compatible and have HW index stored in quirks data. It would be used by TCON
>> TOP driver for configuring muxes.
>
> Can't we use the port/endpoint ID instead? If the mux is the only
> thing that changes, the compatible has no reason to. It's the same IP,
> and the only thing that changes is something that is not part of that
> IP.

I agree. Endpoint IDs should provide that information. I'm still not
sure How to encode multiple in/out mux groups in a device node though.

ChenYu

2018-06-04 11:51:24

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 06/15] drm/sun4i: tcon: Add support for tcon-top

On Fri, Jun 01, 2018 at 09:19:43AM -0700, Chen-Yu Tsai wrote:
> On Fri, Jun 1, 2018 at 8:29 AM, Maxime Ripard <[email protected]> wrote:
> > On Thu, May 31, 2018 at 07:54:08PM +0200, Jernej Škrabec wrote:
> >> Dne četrtek, 31. maj 2018 ob 11:21:33 CEST je Maxime Ripard napisal(a):
> >> > On Thu, May 24, 2018 at 03:01:09PM -0700, Chen-Yu Tsai wrote:
> >> > > >> > > + if (tcon->quirks->needs_tcon_top) {
> >> > > >> > > + struct device_node *np;
> >> > > >> > > +
> >> > > >> > > + np = of_parse_phandle(dev->of_node, "allwinner,tcon-top",
> >> > > >> > > 0);
> >> > > >> > > + if (np) {
> >> > > >> > > + struct platform_device *pdev;
> >> > > >> > > +
> >> > > >> > > + pdev = of_find_device_by_node(np);
> >> > > >> > > + if (pdev)
> >> > > >> > > + tcon->tcon_top =
> >> > > >> > > platform_get_drvdata(pdev);
> >> > > >> > > + of_node_put(np);
> >> > > >> > > +
> >> > > >> > > + if (!tcon->tcon_top)
> >> > > >> > > + return -EPROBE_DEFER;
> >> > > >> > > + }
> >> > > >> > > + }
> >> > > >> > > +
> >> > > >> >
> >> > > >> > I might have missed it, but I've not seen the bindings additions for
> >> > > >> > that property. This shouldn't really be done that way anyway, instead
> >> > > >> > of using a direct phandle, you should be using the of-graph, with the
> >> > > >> > TCON-top sitting where it belongs in the flow of data.
> >> > > >>
> >> > > >> Just to answer to the first question, it did describe it in "[PATCH
> >> > > >> 07/15] dt- bindings: display: sun4i-drm: Add R40 HDMI pipeline".
> >> > > >>
> >> > > >> As why I designed it that way - HW representation could be described
> >> > > >> that way> >>
> >> > > >> (ASCII art makes sense when fixed width font is used to view it):
> >> > > >> / LCD0/LVDS0
> >> > > >>
> >> > > >> / TCON-LCD0
> >> > > >>
> >> > > >> | \ MIPI DSI
> >> > > >>
> >> > > >> mixer0 |
> >> > > >>
> >> > > >> \ / TCON-LCD1 - LCD1/LVDS1
> >> > > >>
> >> > > >> TCON-TOP
> >> > > >>
> >> > > >> / \ TCON-TV0 - TVE0/RGB
> >> > > >>
> >> > > >> mixer1 | \
> >> > > >>
> >> > > >> | TCON-TOP - HDMI
> >> > > >> |
> >> > > >> | /
> >> > > >>
> >> > > >> \ TCON-TV1 - TVE1/RGB
> >> > > >>
> >> > > >> This is a bit simplified, since there is also TVE-TOP, which is
> >> > > >> responsible
> >> > > >> for sharing 4 DACs between both TVE encoders. You can have two TV outs
> >> > > >> (PAL/ NTSC) or TVE0 as TV out and TVE1 as RGB or vice versa. It even
> >> > > >> seems that you can arbitrarly choose which DAC is responsible for
> >> > > >> which signal, so there is a ton of possible end combinations, but I'm
> >> > > >> not 100% sure.
> >> > > >>
> >> > > >> Even though I wrote TCON-TOP twice, this is same unit in HW. R40 manual
> >> > > >> suggest more possibilities, although some of them seem wrong, like RGB
> >> > > >> feeding from LCD TCON. That is confirmed to be wrong when checking BSP
> >> > > >> code.
> >> > > >>
> >> > > >> Additionally, TCON-TOP comes in the middle of TVE0 and LCD0, TVE1 and
> >> > > >> LCD1 for pin muxing, although I'm not sure why is that needed at all,
> >> > > >> since according to R40 datasheet, TVE0 and TVE1 pins are dedicated and
> >> > > >> not on PORT D and PORT H, respectively, as TCON-TOP documentation
> >> > > >> suggest. However, HSYNC and PSYNC lines might be shared between TVE
> >> > > >> (when it works in RGB mode) and LCD. But that is just my guess since
> >> > > >> I'm not really familiar with RGB and LCD interfaces.
> >> > > >>
> >> > > >> I'm really not sure what would be the best representation in OF-graph.
> >> > > >> Can you suggest one?
> >> > > >
> >> > > > Rob might disagree on this one, but I don't see anything wrong with
> >> > > > having loops in the graph. If the TCON-TOP can be both the input and
> >> > > > output of the TCONs, then so be it, and have it described that way in
> >> > > > the graph.
> >> > > >
> >> > > > The code is already able to filter out nodes that have already been
> >> > > > added to the list of devices we need to wait for in the component
> >> > > > framework, so that should work as well.
> >> > > >
> >> > > > And we'd need to describe TVE-TOP as well, even though we don't have a
> >> > > > driver for it yet. That will simplify the backward compatibility later
> >> > > > on.
> >> > >
> >> > > I'm getting the feeling that TCON-TOP / TVE-TOP is the glue layer that
> >> > > binds everything together, and provides signal routing, kind of like
> >> > > DE-TOP on A64. So the signal mux controls that were originally found
> >> > > in TCON0 and TVE0 were moved out.
> >> > >
> >> > > The driver needs to know about that, but the graph about doesn't make
> >> > > much sense directly. Without looking at the manual, I understand it to
> >> > > likely be one mux between the mixers and TCONs, and one between the
> >> > > TCON-TVs and HDMI. Would it make more sense to just have the graph
> >> > > connections between the muxed components, and remove TCON-TOP from
> >> > > it, like we had in the past? A phandle could be used to reference
> >> > > the TCON-TOP for mux controls, in addition to the clocks and resets.
> >> > >
> >> > > For TVE, we would need something to represent each of the output pins,
> >> > > so the device tree can actually describe what kind of signal, be it
> >> > > each component of RGB/YUV or composite video, is wanted on each pin,
> >> > > if any. This is also needed on the A20 for the Cubietruck, so we can
> >> > > describe which pins are tied to the VGA connector, and which one does
> >> > > R, G, or B.
> >> >
> >> > I guess we'll see how the DT maintainers feel about this, but my
> >> > impression is that the OF graph should model the flow of data between
> >> > the devices. If there's a mux somewhere, then the data is definitely
> >> > going through it, and as such it should be part of the graph.
> >>
> >> I concur, but I spent few days thinking how to represent this sanely in graph,
> >> but I didn't find any good solution. I'll represent here my idea and please
> >> tell your opinion before I start implementing it.
> >>
> >> First, let me be clear that mixer0 and mixer1 don't have same capabilities
> >> (different number of planes, mixer0 supports writeback, mixer1 does not,
> >> etc.). Thus, it does matter which mixer is connected to which TCON/encoder.
> >> mixer0 is meant to be connected to main display and mixer1 to auxiliary. That
> >> obviously depends on end system.
> >>
> >> So, TCON TOP has 3 muxes, which have to be represented in graph. Two of them
> >> are for mixer/TCON relationship (each of them 1 input and 4 possible outputs)
> >> and one for TV TCON/HDMI pair selection (2 possible inputs, 1 output).
> >>
> >> According to current practice in sun4i-drm driver, graph has to have port 0,
> >> representing input and port 1, representing output. This would mean that graph
> >> looks something like that:
> >>
> >> tcon_top: tcon-top@1c70000 {
> >> compatible = "allwinner,sun8i-r40-tcon-top";
> >> ...
> >> ports {
> >> #address-cells = <1>;
> >> #size-cells = <0>;
> >>
> >> tcon_top_in: port@0 {
> >> #address-cells = <1>;
> >> #size-cells = <0>;
> >> reg = <0>;
> >>
> >> tcon_top_in_mixer0: endpoint@0 {
> >> reg = <0>;
> >> remote-endpoint = <&mixer0_out_tcon_top>;
> >> };
> >>
> >> tcon_top_in_mixer1: endpoint@1 {
> >> reg = <1>;
> >> remote-endpoint = <&mixer1_out_tcon_top>;
> >> };
> >>
> >> tcon_top_in_tcon_tv: endpoint@2 {
> >> reg = <2>;
> >> // here is HDMI input connection, part of board DTS
> >> remote-endpoint = <board specific phandle to TV TCON output>;
> >> };
> >> };
> >>
> >> tcon_top_out: port@1 {
> >> #address-cells = <1>;
> >> #size-cells = <0>;
> >> reg = <1>;
> >>
> >> tcon_top_out_tcon0: endpoint@0 {
> >> reg = <0>;
> >> // here is mixer0 output connection, part of board DTS
> >> remote-endpoint = <board specific phandle to TCON>;
> >> };
> >>
> >> tcon_top_out_tcon1: endpoint@1 {
> >> reg = <1>;
> >> // here is mixer1 output connection, part of board DTS
> >> remote-endpoint = <board specific phandle to TCON>;
> >> };
> >>
> >> tcon_top_out_hdmi: endpoint@2 {
> >> reg = <2>;
> >> remote-endpoint = <&hdmi_in_tcon_top>;
> >> };
> >> };
> >> };
> >> };
> >
> > IIRC, each port is supposed to be one route for the data, so we would
> > have multiple ports, one for the mixers in input and for the tcon in
> > output, and one for the TCON in input and for the HDMI/TV in
> > output. Rob might correct me here.
> >
> >> tcon_tv0: lcd-controller@1c73000 {
> >> compatible = "allwinner,sun8i-r40-tcon-tv-0";
> >> ...
> >> ports {
> >> #address-cells = <1>;
> >> #size-cells = <0>;
> >>
> >> tcon_tv0_in: port@0 {
> >> reg = <0>;
> >>
> >> tcon_tv0_in_tcon_top: endpoint {
> >> // endpoint depends on board, part of board DTS
> >> remote-endpoint = <phandle to one of tcon_top_out_tcon>;
> >
> > Just curious, what would be there?
> >
> >> };
> >> };
> >>
> >> tcon_tv0_out: port@1 {
> >> #address-cells = <1>;
> >> #size-cells = <0>;
> >> reg = <1>;
> >>
> >> // endpoints to TV TOP and TCON TOP HDMI input
> >> ...
> >> };
> >> };
> >> };
> >>
> >> tcon_tv1: lcd-controller@1c74000 {
> >> compatible = "allwinner,sun8i-r40-tcon-tv-1";
> >> ...
> >> ports {
> >> #address-cells = <1>;
> >> #size-cells = <0>;
> >>
> >> tcon_tv1_in: port@0 {
> >> reg = <0>;
> >>
> >> tcon_tv1_in_tcon_top: endpoint {
> >> // endpoint depends on board, part of board DTS
> >> remote-endpoint = <phandle to one of tcon_top_out_tcon>;
> >> };
> >> };
> >>
> >> tcon_tv1_out: port@1 {
> >> #address-cells = <1>;
> >> #size-cells = <0>;
> >> reg = <1>;
> >>
> >> // endpoints to TV TOP and TCON TOP HDMI input
> >> ...
> >> };
> >> };
> >> };
> >>
> >> tcon_lcd0 and tcon_lcd1 would have similar connections, except that for
> >> outputs would be LCD or LVDS panels or MIPI DSI encoder.
> >>
> >> Please note that each TCON (there are 4 of them) would need to have unique
> >> compatible and have HW index stored in quirks data. It would be used by TCON
> >> TOP driver for configuring muxes.
> >
> > Can't we use the port/endpoint ID instead? If the mux is the only
> > thing that changes, the compatible has no reason to. It's the same IP,
> > and the only thing that changes is something that is not part of that
> > IP.
>
> I agree. Endpoint IDs should provide that information. I'm still not
> sure How to encode multiple in/out mux groups in a device node though.

I guess we can do that through different ports?

Maxime

--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com


Attachments:
(No filename) (12.49 kB)
signature.asc (849.00 B)
Download all attachments

2018-06-04 15:12:41

by Jernej Skrabec

[permalink] [raw]
Subject: Re: [PATCH 06/15] drm/sun4i: tcon: Add support for tcon-top

Dne ponedeljek, 04. junij 2018 ob 13:50:34 CEST je Maxime Ripard napisal(a):
> On Fri, Jun 01, 2018 at 09:19:43AM -0700, Chen-Yu Tsai wrote:
> > On Fri, Jun 1, 2018 at 8:29 AM, Maxime Ripard <[email protected]>
wrote:
> > > On Thu, May 31, 2018 at 07:54:08PM +0200, Jernej Škrabec wrote:
> > >> Dne četrtek, 31. maj 2018 ob 11:21:33 CEST je Maxime Ripard napisal(a):
> > >> > On Thu, May 24, 2018 at 03:01:09PM -0700, Chen-Yu Tsai wrote:
> > >> > > >> > > + if (tcon->quirks->needs_tcon_top) {
> > >> > > >> > > + struct device_node *np;
> > >> > > >> > > +
> > >> > > >> > > + np = of_parse_phandle(dev->of_node,
> > >> > > >> > > "allwinner,tcon-top",
> > >> > > >> > > 0);
> > >> > > >> > > + if (np) {
> > >> > > >> > > + struct platform_device *pdev;
> > >> > > >> > > +
> > >> > > >> > > + pdev = of_find_device_by_node(np);
> > >> > > >> > > + if (pdev)
> > >> > > >> > > + tcon->tcon_top =
> > >> > > >> > > platform_get_drvdata(pdev);
> > >> > > >> > > + of_node_put(np);
> > >> > > >> > > +
> > >> > > >> > > + if (!tcon->tcon_top)
> > >> > > >> > > + return -EPROBE_DEFER;
> > >> > > >> > > + }
> > >> > > >> > > + }
> > >> > > >> > > +
> > >> > > >> >
> > >> > > >> > I might have missed it, but I've not seen the bindings
> > >> > > >> > additions for
> > >> > > >> > that property. This shouldn't really be done that way anyway,
> > >> > > >> > instead
> > >> > > >> > of using a direct phandle, you should be using the of-graph,
> > >> > > >> > with the
> > >> > > >> > TCON-top sitting where it belongs in the flow of data.
> > >> > > >>
> > >> > > >> Just to answer to the first question, it did describe it in
> > >> > > >> "[PATCH
> > >> > > >> 07/15] dt- bindings: display: sun4i-drm: Add R40 HDMI pipeline".
> > >> > > >>
> > >> > > >> As why I designed it that way - HW representation could be
> > >> > > >> described
> > >> > > >> that way> >>
> > >> > > >>
> > >> > > >> (ASCII art makes sense when fixed width font is used to view
it):
> > >> > > >> / LCD0/LVDS0
> > >> > > >>
> > >> > > >> / TCON-LCD0
> > >> > > >>
> > >> > > >> | \ MIPI DSI
> > >> > > >>
> > >> > > >> mixer0 |
> > >> > > >>
> > >> > > >> \ / TCON-LCD1 - LCD1/LVDS1
> > >> > > >>
> > >> > > >> TCON-TOP
> > >> > > >>
> > >> > > >> / \ TCON-TV0 - TVE0/RGB
> > >> > > >>
> > >> > > >> mixer1 | \
> > >> > > >>
> > >> > > >> | TCON-TOP - HDMI
> > >> > > >> |
> > >> > > >> | /
> > >> > > >>
> > >> > > >> \ TCON-TV1 - TVE1/RGB
> > >> > > >>
> > >> > > >> This is a bit simplified, since there is also TVE-TOP, which is
> > >> > > >> responsible
> > >> > > >> for sharing 4 DACs between both TVE encoders. You can have two
> > >> > > >> TV outs
> > >> > > >> (PAL/ NTSC) or TVE0 as TV out and TVE1 as RGB or vice versa. It
> > >> > > >> even
> > >> > > >> seems that you can arbitrarly choose which DAC is responsible
> > >> > > >> for
> > >> > > >> which signal, so there is a ton of possible end combinations,
> > >> > > >> but I'm
> > >> > > >> not 100% sure.
> > >> > > >>
> > >> > > >> Even though I wrote TCON-TOP twice, this is same unit in HW. R40
> > >> > > >> manual
> > >> > > >> suggest more possibilities, although some of them seem wrong,
> > >> > > >> like RGB
> > >> > > >> feeding from LCD TCON. That is confirmed to be wrong when
> > >> > > >> checking BSP
> > >> > > >> code.
> > >> > > >>
> > >> > > >> Additionally, TCON-TOP comes in the middle of TVE0 and LCD0,
> > >> > > >> TVE1 and
> > >> > > >> LCD1 for pin muxing, although I'm not sure why is that needed at
> > >> > > >> all,
> > >> > > >> since according to R40 datasheet, TVE0 and TVE1 pins are
> > >> > > >> dedicated and
> > >> > > >> not on PORT D and PORT H, respectively, as TCON-TOP
> > >> > > >> documentation
> > >> > > >> suggest. However, HSYNC and PSYNC lines might be shared between
> > >> > > >> TVE
> > >> > > >> (when it works in RGB mode) and LCD. But that is just my guess
> > >> > > >> since
> > >> > > >> I'm not really familiar with RGB and LCD interfaces.
> > >> > > >>
> > >> > > >> I'm really not sure what would be the best representation in
> > >> > > >> OF-graph.
> > >> > > >> Can you suggest one?
> > >> > > >
> > >> > > > Rob might disagree on this one, but I don't see anything wrong
> > >> > > > with
> > >> > > > having loops in the graph. If the TCON-TOP can be both the input
> > >> > > > and
> > >> > > > output of the TCONs, then so be it, and have it described that
> > >> > > > way in
> > >> > > > the graph.
> > >> > > >
> > >> > > > The code is already able to filter out nodes that have already
> > >> > > > been
> > >> > > > added to the list of devices we need to wait for in the component
> > >> > > > framework, so that should work as well.
> > >> > > >
> > >> > > > And we'd need to describe TVE-TOP as well, even though we don't
> > >> > > > have a
> > >> > > > driver for it yet. That will simplify the backward compatibility
> > >> > > > later
> > >> > > > on.
> > >> > >
> > >> > > I'm getting the feeling that TCON-TOP / TVE-TOP is the glue layer
> > >> > > that
> > >> > > binds everything together, and provides signal routing, kind of
> > >> > > like
> > >> > > DE-TOP on A64. So the signal mux controls that were originally
> > >> > > found
> > >> > > in TCON0 and TVE0 were moved out.
> > >> > >
> > >> > > The driver needs to know about that, but the graph about doesn't
> > >> > > make
> > >> > > much sense directly. Without looking at the manual, I understand it
> > >> > > to
> > >> > > likely be one mux between the mixers and TCONs, and one between the
> > >> > > TCON-TVs and HDMI. Would it make more sense to just have the graph
> > >> > > connections between the muxed components, and remove TCON-TOP from
> > >> > > it, like we had in the past? A phandle could be used to reference
> > >> > > the TCON-TOP for mux controls, in addition to the clocks and
> > >> > > resets.
> > >> > >
> > >> > > For TVE, we would need something to represent each of the output
> > >> > > pins,
> > >> > > so the device tree can actually describe what kind of signal, be it
> > >> > > each component of RGB/YUV or composite video, is wanted on each
> > >> > > pin,
> > >> > > if any. This is also needed on the A20 for the Cubietruck, so we
> > >> > > can
> > >> > > describe which pins are tied to the VGA connector, and which one
> > >> > > does
> > >> > > R, G, or B.
> > >> >
> > >> > I guess we'll see how the DT maintainers feel about this, but my
> > >> > impression is that the OF graph should model the flow of data between
> > >> > the devices. If there's a mux somewhere, then the data is definitely
> > >> > going through it, and as such it should be part of the graph.
> > >>
> > >> I concur, but I spent few days thinking how to represent this sanely in
> > >> graph, but I didn't find any good solution. I'll represent here my
> > >> idea and please tell your opinion before I start implementing it.
> > >>
> > >> First, let me be clear that mixer0 and mixer1 don't have same
> > >> capabilities
> > >> (different number of planes, mixer0 supports writeback, mixer1 does
> > >> not,
> > >> etc.). Thus, it does matter which mixer is connected to which
> > >> TCON/encoder.
> > >> mixer0 is meant to be connected to main display and mixer1 to
> > >> auxiliary. That obviously depends on end system.
> > >>
> > >> So, TCON TOP has 3 muxes, which have to be represented in graph. Two of
> > >> them are for mixer/TCON relationship (each of them 1 input and 4
> > >> possible outputs) and one for TV TCON/HDMI pair selection (2 possible
> > >> inputs, 1 output).
> > >>
> > >> According to current practice in sun4i-drm driver, graph has to have
> > >> port 0, representing input and port 1, representing output. This would
> > >> mean that graph looks something like that:
> > >>
> > >> tcon_top: tcon-top@1c70000 {
> > >>
> > >> compatible = "allwinner,sun8i-r40-tcon-top";
> > >> ...
> > >> ports {
> > >>
> > >> #address-cells = <1>;
> > >> #size-cells = <0>;
> > >>
> > >> tcon_top_in: port@0 {
> > >>
> > >> #address-cells = <1>;
> > >> #size-cells = <0>;
> > >> reg = <0>;
> > >>
> > >> tcon_top_in_mixer0: endpoint@0 {
> > >>
> > >> reg = <0>;
> > >> remote-endpoint = <&mixer0_out_tcon_top>;
> > >>
> > >> };
> > >>
> > >> tcon_top_in_mixer1: endpoint@1 {
> > >>
> > >> reg = <1>;
> > >> remote-endpoint = <&mixer1_out_tcon_top>;
> > >>
> > >> };
> > >>
> > >> tcon_top_in_tcon_tv: endpoint@2 {
> > >>
> > >> reg = <2>;
> > >> // here is HDMI input connection, part of
> > >> board DTS
> > >> remote-endpoint = <board specific phandle
> > >> to TV TCON output>;
> > >>
> > >> };
> > >>
> > >> };
> > >>
> > >> tcon_top_out: port@1 {
> > >>
> > >> #address-cells = <1>;
> > >> #size-cells = <0>;
> > >> reg = <1>;
> > >>
> > >> tcon_top_out_tcon0: endpoint@0 {
> > >>
> > >> reg = <0>;
> > >> // here is mixer0 output connection, part
> > >> of board DTS
> > >> remote-endpoint = <board specific phandle
> > >> to TCON>;
> > >>
> > >> };
> > >>
> > >> tcon_top_out_tcon1: endpoint@1 {
> > >>
> > >> reg = <1>;
> > >> // here is mixer1 output connection, part
> > >> of board DTS
> > >> remote-endpoint = <board specific phandle
> > >> to TCON>;
> > >>
> > >> };
> > >>
> > >> tcon_top_out_hdmi: endpoint@2 {
> > >>
> > >> reg = <2>;
> > >> remote-endpoint = <&hdmi_in_tcon_top>;
> > >>
> > >> };
> > >>
> > >> };
> > >>
> > >> };
> > >>
> > >> };
> > >
> > > IIRC, each port is supposed to be one route for the data, so we would
> > > have multiple ports, one for the mixers in input and for the tcon in
> > > output, and one for the TCON in input and for the HDMI/TV in
> > > output. Rob might correct me here.

Ok, that seems more clean approach. I'll have to extend graph traversing
algorithm in sun4i_drv.c, but that's no problem.

Just to be clear, you have in mind 3 pairs of ports (0/1 for mixer0 mux, 2/3
for mixer1 and 4/5 for HDMI input), right? That way each mux is represented
with one pair of ports, even numbered for input and odd numbered for output.

> > >
> > >> tcon_tv0: lcd-controller@1c73000 {
> > >>
> > >> compatible = "allwinner,sun8i-r40-tcon-tv-0";
> > >> ...
> > >> ports {
> > >>
> > >> #address-cells = <1>;
> > >> #size-cells = <0>;
> > >>
> > >> tcon_tv0_in: port@0 {
> > >>
> > >> reg = <0>;
> > >>
> > >> tcon_tv0_in_tcon_top: endpoint {
> > >>
> > >> // endpoint depends on board, part of
> > >> board DTS
> > >> remote-endpoint = <phandle to one of
> > >> tcon_top_out_tcon>;
> > >
> > > Just curious, what would be there?

Either phandle to tcon_top_out_tcon0 or tcon_top_out_tcon1.

> > >
> > >> };
> > >>
> > >> };
> > >>
> > >> tcon_tv0_out: port@1 {
> > >>
> > >> #address-cells = <1>;
> > >> #size-cells = <0>;
> > >> reg = <1>;
> > >>
> > >> // endpoints to TV TOP and TCON TOP HDMI input
> > >> ...
> > >>
> > >> };
> > >>
> > >> };
> > >>
> > >> };
> > >>
> > >> tcon_tv1: lcd-controller@1c74000 {
> > >>
> > >> compatible = "allwinner,sun8i-r40-tcon-tv-1";
> > >> ...
> > >> ports {
> > >>
> > >> #address-cells = <1>;
> > >> #size-cells = <0>;
> > >>
> > >> tcon_tv1_in: port@0 {
> > >>
> > >> reg = <0>;
> > >>
> > >> tcon_tv1_in_tcon_top: endpoint {
> > >>
> > >> // endpoint depends on board, part of
> > >> board DTS
> > >> remote-endpoint = <phandle to one of
> > >> tcon_top_out_tcon>;
> > >>
> > >> };
> > >>
> > >> };
> > >>
> > >> tcon_tv1_out: port@1 {
> > >>
> > >> #address-cells = <1>;
> > >> #size-cells = <0>;
> > >> reg = <1>;
> > >>
> > >> // endpoints to TV TOP and TCON TOP HDMI input
> > >> ...
> > >>
> > >> };
> > >>
> > >> };
> > >>
> > >> };
> > >>
> > >> tcon_lcd0 and tcon_lcd1 would have similar connections, except that for
> > >> outputs would be LCD or LVDS panels or MIPI DSI encoder.
> > >>
> > >> Please note that each TCON (there are 4 of them) would need to have
> > >> unique
> > >> compatible and have HW index stored in quirks data. It would be used by
> > >> TCON TOP driver for configuring muxes.
> > >
> > > Can't we use the port/endpoint ID instead? If the mux is the only
> > > thing that changes, the compatible has no reason to. It's the same IP,
> > > and the only thing that changes is something that is not part of that
> > > IP.
> >
> > I agree. Endpoint IDs should provide that information. I'm still not
> > sure How to encode multiple in/out mux groups in a device node though.
>
> I guess we can do that through different ports?

Ok, I'll try to do something with "reg" property.

Best regards,
Jernej



2018-06-04 16:25:12

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 06/15] drm/sun4i: tcon: Add support for tcon-top

On Mon, Jun 04, 2018 at 05:09:56PM +0200, Jernej Škrabec wrote:
> Dne ponedeljek, 04. junij 2018 ob 13:50:34 CEST je Maxime Ripard napisal(a):
> > On Fri, Jun 01, 2018 at 09:19:43AM -0700, Chen-Yu Tsai wrote:
> > > On Fri, Jun 1, 2018 at 8:29 AM, Maxime Ripard <[email protected]>
> wrote:
> > > > On Thu, May 31, 2018 at 07:54:08PM +0200, Jernej Škrabec wrote:
> > > >> Dne četrtek, 31. maj 2018 ob 11:21:33 CEST je Maxime Ripard napisal(a):
> > > >> > On Thu, May 24, 2018 at 03:01:09PM -0700, Chen-Yu Tsai wrote:
> > > >> > > >> > > + if (tcon->quirks->needs_tcon_top) {
> > > >> > > >> > > + struct device_node *np;
> > > >> > > >> > > +
> > > >> > > >> > > + np = of_parse_phandle(dev->of_node,
> > > >> > > >> > > "allwinner,tcon-top",
> > > >> > > >> > > 0);
> > > >> > > >> > > + if (np) {
> > > >> > > >> > > + struct platform_device *pdev;
> > > >> > > >> > > +
> > > >> > > >> > > + pdev = of_find_device_by_node(np);
> > > >> > > >> > > + if (pdev)
> > > >> > > >> > > + tcon->tcon_top =
> > > >> > > >> > > platform_get_drvdata(pdev);
> > > >> > > >> > > + of_node_put(np);
> > > >> > > >> > > +
> > > >> > > >> > > + if (!tcon->tcon_top)
> > > >> > > >> > > + return -EPROBE_DEFER;
> > > >> > > >> > > + }
> > > >> > > >> > > + }
> > > >> > > >> > > +
> > > >> > > >> >
> > > >> > > >> > I might have missed it, but I've not seen the bindings
> > > >> > > >> > additions for
> > > >> > > >> > that property. This shouldn't really be done that way anyway,
> > > >> > > >> > instead
> > > >> > > >> > of using a direct phandle, you should be using the of-graph,
> > > >> > > >> > with the
> > > >> > > >> > TCON-top sitting where it belongs in the flow of data.
> > > >> > > >>
> > > >> > > >> Just to answer to the first question, it did describe it in
> > > >> > > >> "[PATCH
> > > >> > > >> 07/15] dt- bindings: display: sun4i-drm: Add R40 HDMI pipeline".
> > > >> > > >>
> > > >> > > >> As why I designed it that way - HW representation could be
> > > >> > > >> described
> > > >> > > >> that way> >>
> > > >> > > >>
> > > >> > > >> (ASCII art makes sense when fixed width font is used to view
> it):
> > > >> > > >> / LCD0/LVDS0
> > > >> > > >>
> > > >> > > >> / TCON-LCD0
> > > >> > > >>
> > > >> > > >> | \ MIPI DSI
> > > >> > > >>
> > > >> > > >> mixer0 |
> > > >> > > >>
> > > >> > > >> \ / TCON-LCD1 - LCD1/LVDS1
> > > >> > > >>
> > > >> > > >> TCON-TOP
> > > >> > > >>
> > > >> > > >> / \ TCON-TV0 - TVE0/RGB
> > > >> > > >>
> > > >> > > >> mixer1 | \
> > > >> > > >>
> > > >> > > >> | TCON-TOP - HDMI
> > > >> > > >> |
> > > >> > > >> | /
> > > >> > > >>
> > > >> > > >> \ TCON-TV1 - TVE1/RGB
> > > >> > > >>
> > > >> > > >> This is a bit simplified, since there is also TVE-TOP, which is
> > > >> > > >> responsible
> > > >> > > >> for sharing 4 DACs between both TVE encoders. You can have two
> > > >> > > >> TV outs
> > > >> > > >> (PAL/ NTSC) or TVE0 as TV out and TVE1 as RGB or vice versa. It
> > > >> > > >> even
> > > >> > > >> seems that you can arbitrarly choose which DAC is responsible
> > > >> > > >> for
> > > >> > > >> which signal, so there is a ton of possible end combinations,
> > > >> > > >> but I'm
> > > >> > > >> not 100% sure.
> > > >> > > >>
> > > >> > > >> Even though I wrote TCON-TOP twice, this is same unit in HW. R40
> > > >> > > >> manual
> > > >> > > >> suggest more possibilities, although some of them seem wrong,
> > > >> > > >> like RGB
> > > >> > > >> feeding from LCD TCON. That is confirmed to be wrong when
> > > >> > > >> checking BSP
> > > >> > > >> code.
> > > >> > > >>
> > > >> > > >> Additionally, TCON-TOP comes in the middle of TVE0 and LCD0,
> > > >> > > >> TVE1 and
> > > >> > > >> LCD1 for pin muxing, although I'm not sure why is that needed at
> > > >> > > >> all,
> > > >> > > >> since according to R40 datasheet, TVE0 and TVE1 pins are
> > > >> > > >> dedicated and
> > > >> > > >> not on PORT D and PORT H, respectively, as TCON-TOP
> > > >> > > >> documentation
> > > >> > > >> suggest. However, HSYNC and PSYNC lines might be shared between
> > > >> > > >> TVE
> > > >> > > >> (when it works in RGB mode) and LCD. But that is just my guess
> > > >> > > >> since
> > > >> > > >> I'm not really familiar with RGB and LCD interfaces.
> > > >> > > >>
> > > >> > > >> I'm really not sure what would be the best representation in
> > > >> > > >> OF-graph.
> > > >> > > >> Can you suggest one?
> > > >> > > >
> > > >> > > > Rob might disagree on this one, but I don't see anything wrong
> > > >> > > > with
> > > >> > > > having loops in the graph. If the TCON-TOP can be both the input
> > > >> > > > and
> > > >> > > > output of the TCONs, then so be it, and have it described that
> > > >> > > > way in
> > > >> > > > the graph.
> > > >> > > >
> > > >> > > > The code is already able to filter out nodes that have already
> > > >> > > > been
> > > >> > > > added to the list of devices we need to wait for in the component
> > > >> > > > framework, so that should work as well.
> > > >> > > >
> > > >> > > > And we'd need to describe TVE-TOP as well, even though we don't
> > > >> > > > have a
> > > >> > > > driver for it yet. That will simplify the backward compatibility
> > > >> > > > later
> > > >> > > > on.
> > > >> > >
> > > >> > > I'm getting the feeling that TCON-TOP / TVE-TOP is the glue layer
> > > >> > > that
> > > >> > > binds everything together, and provides signal routing, kind of
> > > >> > > like
> > > >> > > DE-TOP on A64. So the signal mux controls that were originally
> > > >> > > found
> > > >> > > in TCON0 and TVE0 were moved out.
> > > >> > >
> > > >> > > The driver needs to know about that, but the graph about doesn't
> > > >> > > make
> > > >> > > much sense directly. Without looking at the manual, I understand it
> > > >> > > to
> > > >> > > likely be one mux between the mixers and TCONs, and one between the
> > > >> > > TCON-TVs and HDMI. Would it make more sense to just have the graph
> > > >> > > connections between the muxed components, and remove TCON-TOP from
> > > >> > > it, like we had in the past? A phandle could be used to reference
> > > >> > > the TCON-TOP for mux controls, in addition to the clocks and
> > > >> > > resets.
> > > >> > >
> > > >> > > For TVE, we would need something to represent each of the output
> > > >> > > pins,
> > > >> > > so the device tree can actually describe what kind of signal, be it
> > > >> > > each component of RGB/YUV or composite video, is wanted on each
> > > >> > > pin,
> > > >> > > if any. This is also needed on the A20 for the Cubietruck, so we
> > > >> > > can
> > > >> > > describe which pins are tied to the VGA connector, and which one
> > > >> > > does
> > > >> > > R, G, or B.
> > > >> >
> > > >> > I guess we'll see how the DT maintainers feel about this, but my
> > > >> > impression is that the OF graph should model the flow of data between
> > > >> > the devices. If there's a mux somewhere, then the data is definitely
> > > >> > going through it, and as such it should be part of the graph.
> > > >>
> > > >> I concur, but I spent few days thinking how to represent this sanely in
> > > >> graph, but I didn't find any good solution. I'll represent here my
> > > >> idea and please tell your opinion before I start implementing it.
> > > >>
> > > >> First, let me be clear that mixer0 and mixer1 don't have same
> > > >> capabilities
> > > >> (different number of planes, mixer0 supports writeback, mixer1 does
> > > >> not,
> > > >> etc.). Thus, it does matter which mixer is connected to which
> > > >> TCON/encoder.
> > > >> mixer0 is meant to be connected to main display and mixer1 to
> > > >> auxiliary. That obviously depends on end system.
> > > >>
> > > >> So, TCON TOP has 3 muxes, which have to be represented in graph. Two of
> > > >> them are for mixer/TCON relationship (each of them 1 input and 4
> > > >> possible outputs) and one for TV TCON/HDMI pair selection (2 possible
> > > >> inputs, 1 output).
> > > >>
> > > >> According to current practice in sun4i-drm driver, graph has to have
> > > >> port 0, representing input and port 1, representing output. This would
> > > >> mean that graph looks something like that:
> > > >>
> > > >> tcon_top: tcon-top@1c70000 {
> > > >>
> > > >> compatible = "allwinner,sun8i-r40-tcon-top";
> > > >> ...
> > > >> ports {
> > > >>
> > > >> #address-cells = <1>;
> > > >> #size-cells = <0>;
> > > >>
> > > >> tcon_top_in: port@0 {
> > > >>
> > > >> #address-cells = <1>;
> > > >> #size-cells = <0>;
> > > >> reg = <0>;
> > > >>
> > > >> tcon_top_in_mixer0: endpoint@0 {
> > > >>
> > > >> reg = <0>;
> > > >> remote-endpoint = <&mixer0_out_tcon_top>;
> > > >>
> > > >> };
> > > >>
> > > >> tcon_top_in_mixer1: endpoint@1 {
> > > >>
> > > >> reg = <1>;
> > > >> remote-endpoint = <&mixer1_out_tcon_top>;
> > > >>
> > > >> };
> > > >>
> > > >> tcon_top_in_tcon_tv: endpoint@2 {
> > > >>
> > > >> reg = <2>;
> > > >> // here is HDMI input connection, part of
> > > >> board DTS
> > > >> remote-endpoint = <board specific phandle
> > > >> to TV TCON output>;
> > > >>
> > > >> };
> > > >>
> > > >> };
> > > >>
> > > >> tcon_top_out: port@1 {
> > > >>
> > > >> #address-cells = <1>;
> > > >> #size-cells = <0>;
> > > >> reg = <1>;
> > > >>
> > > >> tcon_top_out_tcon0: endpoint@0 {
> > > >>
> > > >> reg = <0>;
> > > >> // here is mixer0 output connection, part
> > > >> of board DTS
> > > >> remote-endpoint = <board specific phandle
> > > >> to TCON>;
> > > >>
> > > >> };
> > > >>
> > > >> tcon_top_out_tcon1: endpoint@1 {
> > > >>
> > > >> reg = <1>;
> > > >> // here is mixer1 output connection, part
> > > >> of board DTS
> > > >> remote-endpoint = <board specific phandle
> > > >> to TCON>;
> > > >>
> > > >> };
> > > >>
> > > >> tcon_top_out_hdmi: endpoint@2 {
> > > >>
> > > >> reg = <2>;
> > > >> remote-endpoint = <&hdmi_in_tcon_top>;
> > > >>
> > > >> };
> > > >>
> > > >> };
> > > >>
> > > >> };
> > > >>
> > > >> };
> > > >
> > > > IIRC, each port is supposed to be one route for the data, so we would
> > > > have multiple ports, one for the mixers in input and for the tcon in
> > > > output, and one for the TCON in input and for the HDMI/TV in
> > > > output. Rob might correct me here.
>
> Ok, that seems more clean approach. I'll have to extend graph traversing
> algorithm in sun4i_drv.c, but that's no problem.
>
> Just to be clear, you have in mind 3 pairs of ports (0/1 for mixer0 mux, 2/3
> for mixer1 and 4/5 for HDMI input), right? That way each mux is represented
> with one pair of ports, even numbered for input and odd numbered for output.

Yep, unless Rob feels otherwise.

Maxime

--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com


Attachments:
(No filename) (12.79 kB)
signature.asc (849.00 B)
Download all attachments

2018-06-06 22:46:20

by Jernej Skrabec

[permalink] [raw]
Subject: Re: [PATCH 06/15] drm/sun4i: tcon: Add support for tcon-top

Dne ponedeljek, 04. junij 2018 ob 18:23:57 CEST je Maxime Ripard napisal(a):
> On Mon, Jun 04, 2018 at 05:09:56PM +0200, Jernej Škrabec wrote:
> > Dne ponedeljek, 04. junij 2018 ob 13:50:34 CEST je Maxime Ripard
napisal(a):
> > > On Fri, Jun 01, 2018 at 09:19:43AM -0700, Chen-Yu Tsai wrote:
> > > > On Fri, Jun 1, 2018 at 8:29 AM, Maxime Ripard
> > > > <[email protected]>
> >
> > wrote:
> > > > > On Thu, May 31, 2018 at 07:54:08PM +0200, Jernej Škrabec wrote:
> > > > >> Dne četrtek, 31. maj 2018 ob 11:21:33 CEST je Maxime Ripard
napisal(a):
> > > > >> > On Thu, May 24, 2018 at 03:01:09PM -0700, Chen-Yu Tsai wrote:
> > > > >> > > >> > > + if (tcon->quirks->needs_tcon_top) {
> > > > >> > > >> > > + struct device_node *np;
> > > > >> > > >> > > +
> > > > >> > > >> > > + np = of_parse_phandle(dev->of_node,
> > > > >> > > >> > > "allwinner,tcon-top",
> > > > >> > > >> > > 0);
> > > > >> > > >> > > + if (np) {
> > > > >> > > >> > > + struct platform_device *pdev;
> > > > >> > > >> > > +
> > > > >> > > >> > > + pdev = of_find_device_by_node(np);
> > > > >> > > >> > > + if (pdev)
> > > > >> > > >> > > + tcon->tcon_top =
> > > > >> > > >> > > platform_get_drvdata(pdev);
> > > > >> > > >> > > + of_node_put(np);
> > > > >> > > >> > > +
> > > > >> > > >> > > + if (!tcon->tcon_top)
> > > > >> > > >> > > + return -EPROBE_DEFER;
> > > > >> > > >> > > + }
> > > > >> > > >> > > + }
> > > > >> > > >> > > +
> > > > >> > > >> >
> > > > >> > > >> > I might have missed it, but I've not seen the bindings
> > > > >> > > >> > additions for
> > > > >> > > >> > that property. This shouldn't really be done that way
> > > > >> > > >> > anyway,
> > > > >> > > >> > instead
> > > > >> > > >> > of using a direct phandle, you should be using the
> > > > >> > > >> > of-graph,
> > > > >> > > >> > with the
> > > > >> > > >> > TCON-top sitting where it belongs in the flow of data.
> > > > >> > > >>
> > > > >> > > >> Just to answer to the first question, it did describe it in
> > > > >> > > >> "[PATCH
> > > > >> > > >> 07/15] dt- bindings: display: sun4i-drm: Add R40 HDMI
> > > > >> > > >> pipeline".
> > > > >> > > >>
> > > > >> > > >> As why I designed it that way - HW representation could be
> > > > >> > > >> described
> > > > >> > > >> that way> >>
> > > > >> > > >>
> > > > >> > > >> (ASCII art makes sense when fixed width font is used to view
> >
> > it):
> > > > >> > > >> / LCD0/LVDS0
> > > > >> > > >>
> > > > >> > > >> / TCON-LCD0
> > > > >> > > >>
> > > > >> > > >> | \ MIPI DSI
> > > > >> > > >>
> > > > >> > > >> mixer0 |
> > > > >> > > >>
> > > > >> > > >> \ / TCON-LCD1 - LCD1/LVDS1
> > > > >> > > >>
> > > > >> > > >> TCON-TOP
> > > > >> > > >>
> > > > >> > > >> / \ TCON-TV0 - TVE0/RGB
> > > > >> > > >>
> > > > >> > > >> mixer1 | \
> > > > >> > > >>
> > > > >> > > >> | TCON-TOP - HDMI
> > > > >> > > >> |
> > > > >> > > >> | /
> > > > >> > > >>
> > > > >> > > >> \ TCON-TV1 - TVE1/RGB
> > > > >> > > >>
> > > > >> > > >> This is a bit simplified, since there is also TVE-TOP, which
> > > > >> > > >> is
> > > > >> > > >> responsible
> > > > >> > > >> for sharing 4 DACs between both TVE encoders. You can have
> > > > >> > > >> two
> > > > >> > > >> TV outs
> > > > >> > > >> (PAL/ NTSC) or TVE0 as TV out and TVE1 as RGB or vice versa.
> > > > >> > > >> It
> > > > >> > > >> even
> > > > >> > > >> seems that you can arbitrarly choose which DAC is
> > > > >> > > >> responsible
> > > > >> > > >> for
> > > > >> > > >> which signal, so there is a ton of possible end
> > > > >> > > >> combinations,
> > > > >> > > >> but I'm
> > > > >> > > >> not 100% sure.
> > > > >> > > >>
> > > > >> > > >> Even though I wrote TCON-TOP twice, this is same unit in HW.
> > > > >> > > >> R40
> > > > >> > > >> manual
> > > > >> > > >> suggest more possibilities, although some of them seem
> > > > >> > > >> wrong,
> > > > >> > > >> like RGB
> > > > >> > > >> feeding from LCD TCON. That is confirmed to be wrong when
> > > > >> > > >> checking BSP
> > > > >> > > >> code.
> > > > >> > > >>
> > > > >> > > >> Additionally, TCON-TOP comes in the middle of TVE0 and LCD0,
> > > > >> > > >> TVE1 and
> > > > >> > > >> LCD1 for pin muxing, although I'm not sure why is that
> > > > >> > > >> needed at
> > > > >> > > >> all,
> > > > >> > > >> since according to R40 datasheet, TVE0 and TVE1 pins are
> > > > >> > > >> dedicated and
> > > > >> > > >> not on PORT D and PORT H, respectively, as TCON-TOP
> > > > >> > > >> documentation
> > > > >> > > >> suggest. However, HSYNC and PSYNC lines might be shared
> > > > >> > > >> between
> > > > >> > > >> TVE
> > > > >> > > >> (when it works in RGB mode) and LCD. But that is just my
> > > > >> > > >> guess
> > > > >> > > >> since
> > > > >> > > >> I'm not really familiar with RGB and LCD interfaces.
> > > > >> > > >>
> > > > >> > > >> I'm really not sure what would be the best representation in
> > > > >> > > >> OF-graph.
> > > > >> > > >> Can you suggest one?
> > > > >> > > >
> > > > >> > > > Rob might disagree on this one, but I don't see anything
> > > > >> > > > wrong
> > > > >> > > > with
> > > > >> > > > having loops in the graph. If the TCON-TOP can be both the
> > > > >> > > > input
> > > > >> > > > and
> > > > >> > > > output of the TCONs, then so be it, and have it described
> > > > >> > > > that
> > > > >> > > > way in
> > > > >> > > > the graph.
> > > > >> > > >
> > > > >> > > > The code is already able to filter out nodes that have
> > > > >> > > > already
> > > > >> > > > been
> > > > >> > > > added to the list of devices we need to wait for in the
> > > > >> > > > component
> > > > >> > > > framework, so that should work as well.
> > > > >> > > >
> > > > >> > > > And we'd need to describe TVE-TOP as well, even though we
> > > > >> > > > don't
> > > > >> > > > have a
> > > > >> > > > driver for it yet. That will simplify the backward
> > > > >> > > > compatibility
> > > > >> > > > later
> > > > >> > > > on.
> > > > >> > >
> > > > >> > > I'm getting the feeling that TCON-TOP / TVE-TOP is the glue
> > > > >> > > layer
> > > > >> > > that
> > > > >> > > binds everything together, and provides signal routing, kind of
> > > > >> > > like
> > > > >> > > DE-TOP on A64. So the signal mux controls that were originally
> > > > >> > > found
> > > > >> > > in TCON0 and TVE0 were moved out.
> > > > >> > >
> > > > >> > > The driver needs to know about that, but the graph about
> > > > >> > > doesn't
> > > > >> > > make
> > > > >> > > much sense directly. Without looking at the manual, I
> > > > >> > > understand it
> > > > >> > > to
> > > > >> > > likely be one mux between the mixers and TCONs, and one between
> > > > >> > > the
> > > > >> > > TCON-TVs and HDMI. Would it make more sense to just have the
> > > > >> > > graph
> > > > >> > > connections between the muxed components, and remove TCON-TOP
> > > > >> > > from
> > > > >> > > it, like we had in the past? A phandle could be used to
> > > > >> > > reference
> > > > >> > > the TCON-TOP for mux controls, in addition to the clocks and
> > > > >> > > resets.
> > > > >> > >
> > > > >> > > For TVE, we would need something to represent each of the
> > > > >> > > output
> > > > >> > > pins,
> > > > >> > > so the device tree can actually describe what kind of signal,
> > > > >> > > be it
> > > > >> > > each component of RGB/YUV or composite video, is wanted on each
> > > > >> > > pin,
> > > > >> > > if any. This is also needed on the A20 for the Cubietruck, so
> > > > >> > > we
> > > > >> > > can
> > > > >> > > describe which pins are tied to the VGA connector, and which
> > > > >> > > one
> > > > >> > > does
> > > > >> > > R, G, or B.
> > > > >> >
> > > > >> > I guess we'll see how the DT maintainers feel about this, but my
> > > > >> > impression is that the OF graph should model the flow of data
> > > > >> > between
> > > > >> > the devices. If there's a mux somewhere, then the data is
> > > > >> > definitely
> > > > >> > going through it, and as such it should be part of the graph.
> > > > >>
> > > > >> I concur, but I spent few days thinking how to represent this
> > > > >> sanely in
> > > > >> graph, but I didn't find any good solution. I'll represent here my
> > > > >> idea and please tell your opinion before I start implementing it.
> > > > >>
> > > > >> First, let me be clear that mixer0 and mixer1 don't have same
> > > > >> capabilities
> > > > >> (different number of planes, mixer0 supports writeback, mixer1 does
> > > > >> not,
> > > > >> etc.). Thus, it does matter which mixer is connected to which
> > > > >> TCON/encoder.
> > > > >> mixer0 is meant to be connected to main display and mixer1 to
> > > > >> auxiliary. That obviously depends on end system.
> > > > >>
> > > > >> So, TCON TOP has 3 muxes, which have to be represented in graph.
> > > > >> Two of
> > > > >> them are for mixer/TCON relationship (each of them 1 input and 4
> > > > >> possible outputs) and one for TV TCON/HDMI pair selection (2
> > > > >> possible
> > > > >> inputs, 1 output).
> > > > >>
> > > > >> According to current practice in sun4i-drm driver, graph has to
> > > > >> have
> > > > >> port 0, representing input and port 1, representing output. This
> > > > >> would
> > > > >> mean that graph looks something like that:
> > > > >>
> > > > >> tcon_top: tcon-top@1c70000 {
> > > > >>
> > > > >> compatible = "allwinner,sun8i-r40-tcon-top";
> > > > >> ...
> > > > >> ports {
> > > > >>
> > > > >> #address-cells = <1>;
> > > > >> #size-cells = <0>;
> > > > >>
> > > > >> tcon_top_in: port@0 {
> > > > >>
> > > > >> #address-cells = <1>;
> > > > >> #size-cells = <0>;
> > > > >> reg = <0>;
> > > > >>
> > > > >> tcon_top_in_mixer0: endpoint@0 {
> > > > >>
> > > > >> reg = <0>;
> > > > >> remote-endpoint =
> > > > >> <&mixer0_out_tcon_top>;
> > > > >>
> > > > >> };
> > > > >>
> > > > >> tcon_top_in_mixer1: endpoint@1 {
> > > > >>
> > > > >> reg = <1>;
> > > > >> remote-endpoint =
> > > > >> <&mixer1_out_tcon_top>;
> > > > >>
> > > > >> };
> > > > >>
> > > > >> tcon_top_in_tcon_tv: endpoint@2 {
> > > > >>
> > > > >> reg = <2>;
> > > > >> // here is HDMI input connection,
> > > > >> part of
> > > > >> board DTS
> > > > >> remote-endpoint = <board specific
> > > > >> phandle
> > > > >> to TV TCON output>;
> > > > >>
> > > > >> };
> > > > >>
> > > > >> };
> > > > >>
> > > > >> tcon_top_out: port@1 {
> > > > >>
> > > > >> #address-cells = <1>;
> > > > >> #size-cells = <0>;
> > > > >> reg = <1>;
> > > > >>
> > > > >> tcon_top_out_tcon0: endpoint@0 {
> > > > >>
> > > > >> reg = <0>;
> > > > >> // here is mixer0 output connection,
> > > > >> part
> > > > >> of board DTS
> > > > >> remote-endpoint = <board specific
> > > > >> phandle
> > > > >> to TCON>;
> > > > >>
> > > > >> };
> > > > >>
> > > > >> tcon_top_out_tcon1: endpoint@1 {
> > > > >>
> > > > >> reg = <1>;
> > > > >> // here is mixer1 output connection,
> > > > >> part
> > > > >> of board DTS
> > > > >> remote-endpoint = <board specific
> > > > >> phandle
> > > > >> to TCON>;
> > > > >>
> > > > >> };
> > > > >>
> > > > >> tcon_top_out_hdmi: endpoint@2 {
> > > > >>
> > > > >> reg = <2>;
> > > > >> remote-endpoint =
> > > > >> <&hdmi_in_tcon_top>;
> > > > >>
> > > > >> };
> > > > >>
> > > > >> };
> > > > >>
> > > > >> };
> > > > >>
> > > > >> };
> > > > >
> > > > > IIRC, each port is supposed to be one route for the data, so we
> > > > > would
> > > > > have multiple ports, one for the mixers in input and for the tcon in
> > > > > output, and one for the TCON in input and for the HDMI/TV in
> > > > > output. Rob might correct me here.
> >
> > Ok, that seems more clean approach. I'll have to extend graph traversing
> > algorithm in sun4i_drv.c, but that's no problem.
> >
> > Just to be clear, you have in mind 3 pairs of ports (0/1 for mixer0 mux,
> > 2/3 for mixer1 and 4/5 for HDMI input), right? That way each mux is
> > represented with one pair of ports, even numbered for input and odd
> > numbered for output.
> Yep, unless Rob feels otherwise.

I found an issue with this concept.

HDMI driver (sun8i_dw_hdmi.c) uses drm_of_find_possible_crtcs() to find
connected crtcs (TCONs) to HDMI. This function assumes that crtc and encoder
are directly connected through of_graph, but that is not the case with TCON
TOP HDMI mux anymore.
I could give TCON TOP node as an input to this function, but that won't work,
since TCON TOP can have connections to other crtcs, not only that of HDMI and
they will also be picked up by drm_of_find_possible_crtcs().

Any suggestion how to solve this nicely? I think creating my own version of
drm_of_find_possible_crtcs() which considers that case is one way, but not
very nice solution. Alternatively, we can fix possible_crtcs to BIT(0), since
it always has only one input. This is done in meson_dw_hdmi.c for example.

Best regards,
Jernej




2018-06-08 05:19:28

by Jernej Škrabec

[permalink] [raw]
Subject: Re: [linux-sunxi] Re: [PATCH 06/15] drm/sun4i: tcon: Add support for tcon-top

Dne četrtek, 07. junij 2018 ob 00:30:24 CEST je Jernej Škrabec napisal(a):
> Dne ponedeljek, 04. junij 2018 ob 18:23:57 CEST je Maxime Ripard napisal(a):
> > On Mon, Jun 04, 2018 at 05:09:56PM +0200, Jernej Škrabec wrote:
> > > Dne ponedeljek, 04. junij 2018 ob 13:50:34 CEST je Maxime Ripard
>
> napisal(a):
> > > > On Fri, Jun 01, 2018 at 09:19:43AM -0700, Chen-Yu Tsai wrote:
> > > > > On Fri, Jun 1, 2018 at 8:29 AM, Maxime Ripard
> > > > > <[email protected]>
> > >
> > > wrote:
> > > > > > On Thu, May 31, 2018 at 07:54:08PM +0200, Jernej Škrabec wrote:
> > > > > >> Dne četrtek, 31. maj 2018 ob 11:21:33 CEST je Maxime Ripard
>
> napisal(a):
> > > > > >> > On Thu, May 24, 2018 at 03:01:09PM -0700, Chen-Yu Tsai wrote:
> > > > > >> > > >> > > + if (tcon->quirks->needs_tcon_top) {
> > > > > >> > > >> > > + struct device_node *np;
> > > > > >> > > >> > > +
> > > > > >> > > >> > > + np = of_parse_phandle(dev->of_node,
> > > > > >> > > >> > > "allwinner,tcon-top",
> > > > > >> > > >> > > 0);
> > > > > >> > > >> > > + if (np) {
> > > > > >> > > >> > > + struct platform_device *pdev;
> > > > > >> > > >> > > +
> > > > > >> > > >> > > + pdev = of_find_device_by_node(np);
> > > > > >> > > >> > > + if (pdev)
> > > > > >> > > >> > > + tcon->tcon_top =
> > > > > >> > > >> > > platform_get_drvdata(pdev);
> > > > > >> > > >> > > + of_node_put(np);
> > > > > >> > > >> > > +
> > > > > >> > > >> > > + if (!tcon->tcon_top)
> > > > > >> > > >> > > + return -EPROBE_DEFER;
> > > > > >> > > >> > > + }
> > > > > >> > > >> > > + }
> > > > > >> > > >> > > +
> > > > > >> > > >> >
> > > > > >> > > >> > I might have missed it, but I've not seen the bindings
> > > > > >> > > >> > additions for
> > > > > >> > > >> > that property. This shouldn't really be done that way
> > > > > >> > > >> > anyway,
> > > > > >> > > >> > instead
> > > > > >> > > >> > of using a direct phandle, you should be using the
> > > > > >> > > >> > of-graph,
> > > > > >> > > >> > with the
> > > > > >> > > >> > TCON-top sitting where it belongs in the flow of data.
> > > > > >> > > >>
> > > > > >> > > >> Just to answer to the first question, it did describe it
> > > > > >> > > >> in
> > > > > >> > > >> "[PATCH
> > > > > >> > > >> 07/15] dt- bindings: display: sun4i-drm: Add R40 HDMI
> > > > > >> > > >> pipeline".
> > > > > >> > > >>
> > > > > >> > > >> As why I designed it that way - HW representation could be
> > > > > >> > > >> described
> > > > > >> > > >> that way> >>
> > > > > >> > > >>
> > > > > >> > > >> (ASCII art makes sense when fixed width font is used to
> > > > > >> > > >> view
> > >
> > > it):
> > > > > >> > > >> / LCD0/LVDS0
> > > > > >> > > >>
> > > > > >> > > >> / TCON-LCD0
> > > > > >> > > >>
> > > > > >> > > >> | \ MIPI DSI
> > > > > >> > > >>
> > > > > >> > > >> mixer0 |
> > > > > >> > > >>
> > > > > >> > > >> \ / TCON-LCD1 - LCD1/LVDS1
> > > > > >> > > >>
> > > > > >> > > >> TCON-TOP
> > > > > >> > > >>
> > > > > >> > > >> / \ TCON-TV0 - TVE0/RGB
> > > > > >> > > >>
> > > > > >> > > >> mixer1 | \
> > > > > >> > > >>
> > > > > >> > > >> | TCON-TOP - HDMI
> > > > > >> > > >> |
> > > > > >> > > >> | /
> > > > > >> > > >>
> > > > > >> > > >> \ TCON-TV1 - TVE1/RGB
> > > > > >> > > >>
> > > > > >> > > >> This is a bit simplified, since there is also TVE-TOP,
> > > > > >> > > >> which
> > > > > >> > > >> is
> > > > > >> > > >> responsible
> > > > > >> > > >> for sharing 4 DACs between both TVE encoders. You can have
> > > > > >> > > >> two
> > > > > >> > > >> TV outs
> > > > > >> > > >> (PAL/ NTSC) or TVE0 as TV out and TVE1 as RGB or vice
> > > > > >> > > >> versa.
> > > > > >> > > >> It
> > > > > >> > > >> even
> > > > > >> > > >> seems that you can arbitrarly choose which DAC is
> > > > > >> > > >> responsible
> > > > > >> > > >> for
> > > > > >> > > >> which signal, so there is a ton of possible end
> > > > > >> > > >> combinations,
> > > > > >> > > >> but I'm
> > > > > >> > > >> not 100% sure.
> > > > > >> > > >>
> > > > > >> > > >> Even though I wrote TCON-TOP twice, this is same unit in
> > > > > >> > > >> HW.
> > > > > >> > > >> R40
> > > > > >> > > >> manual
> > > > > >> > > >> suggest more possibilities, although some of them seem
> > > > > >> > > >> wrong,
> > > > > >> > > >> like RGB
> > > > > >> > > >> feeding from LCD TCON. That is confirmed to be wrong when
> > > > > >> > > >> checking BSP
> > > > > >> > > >> code.
> > > > > >> > > >>
> > > > > >> > > >> Additionally, TCON-TOP comes in the middle of TVE0 and
> > > > > >> > > >> LCD0,
> > > > > >> > > >> TVE1 and
> > > > > >> > > >> LCD1 for pin muxing, although I'm not sure why is that
> > > > > >> > > >> needed at
> > > > > >> > > >> all,
> > > > > >> > > >> since according to R40 datasheet, TVE0 and TVE1 pins are
> > > > > >> > > >> dedicated and
> > > > > >> > > >> not on PORT D and PORT H, respectively, as TCON-TOP
> > > > > >> > > >> documentation
> > > > > >> > > >> suggest. However, HSYNC and PSYNC lines might be shared
> > > > > >> > > >> between
> > > > > >> > > >> TVE
> > > > > >> > > >> (when it works in RGB mode) and LCD. But that is just my
> > > > > >> > > >> guess
> > > > > >> > > >> since
> > > > > >> > > >> I'm not really familiar with RGB and LCD interfaces.
> > > > > >> > > >>
> > > > > >> > > >> I'm really not sure what would be the best representation
> > > > > >> > > >> in
> > > > > >> > > >> OF-graph.
> > > > > >> > > >> Can you suggest one?
> > > > > >> > > >
> > > > > >> > > > Rob might disagree on this one, but I don't see anything
> > > > > >> > > > wrong
> > > > > >> > > > with
> > > > > >> > > > having loops in the graph. If the TCON-TOP can be both the
> > > > > >> > > > input
> > > > > >> > > > and
> > > > > >> > > > output of the TCONs, then so be it, and have it described
> > > > > >> > > > that
> > > > > >> > > > way in
> > > > > >> > > > the graph.
> > > > > >> > > >
> > > > > >> > > > The code is already able to filter out nodes that have
> > > > > >> > > > already
> > > > > >> > > > been
> > > > > >> > > > added to the list of devices we need to wait for in the
> > > > > >> > > > component
> > > > > >> > > > framework, so that should work as well.
> > > > > >> > > >
> > > > > >> > > > And we'd need to describe TVE-TOP as well, even though we
> > > > > >> > > > don't
> > > > > >> > > > have a
> > > > > >> > > > driver for it yet. That will simplify the backward
> > > > > >> > > > compatibility
> > > > > >> > > > later
> > > > > >> > > > on.
> > > > > >> > >
> > > > > >> > > I'm getting the feeling that TCON-TOP / TVE-TOP is the glue
> > > > > >> > > layer
> > > > > >> > > that
> > > > > >> > > binds everything together, and provides signal routing, kind
> > > > > >> > > of
> > > > > >> > > like
> > > > > >> > > DE-TOP on A64. So the signal mux controls that were
> > > > > >> > > originally
> > > > > >> > > found
> > > > > >> > > in TCON0 and TVE0 were moved out.
> > > > > >> > >
> > > > > >> > > The driver needs to know about that, but the graph about
> > > > > >> > > doesn't
> > > > > >> > > make
> > > > > >> > > much sense directly. Without looking at the manual, I
> > > > > >> > > understand it
> > > > > >> > > to
> > > > > >> > > likely be one mux between the mixers and TCONs, and one
> > > > > >> > > between
> > > > > >> > > the
> > > > > >> > > TCON-TVs and HDMI. Would it make more sense to just have the
> > > > > >> > > graph
> > > > > >> > > connections between the muxed components, and remove TCON-TOP
> > > > > >> > > from
> > > > > >> > > it, like we had in the past? A phandle could be used to
> > > > > >> > > reference
> > > > > >> > > the TCON-TOP for mux controls, in addition to the clocks and
> > > > > >> > > resets.
> > > > > >> > >
> > > > > >> > > For TVE, we would need something to represent each of the
> > > > > >> > > output
> > > > > >> > > pins,
> > > > > >> > > so the device tree can actually describe what kind of signal,
> > > > > >> > > be it
> > > > > >> > > each component of RGB/YUV or composite video, is wanted on
> > > > > >> > > each
> > > > > >> > > pin,
> > > > > >> > > if any. This is also needed on the A20 for the Cubietruck, so
> > > > > >> > > we
> > > > > >> > > can
> > > > > >> > > describe which pins are tied to the VGA connector, and which
> > > > > >> > > one
> > > > > >> > > does
> > > > > >> > > R, G, or B.
> > > > > >> >
> > > > > >> > I guess we'll see how the DT maintainers feel about this, but
> > > > > >> > my
> > > > > >> > impression is that the OF graph should model the flow of data
> > > > > >> > between
> > > > > >> > the devices. If there's a mux somewhere, then the data is
> > > > > >> > definitely
> > > > > >> > going through it, and as such it should be part of the graph.
> > > > > >>
> > > > > >> I concur, but I spent few days thinking how to represent this
> > > > > >> sanely in
> > > > > >> graph, but I didn't find any good solution. I'll represent here
> > > > > >> my
> > > > > >> idea and please tell your opinion before I start implementing it.
> > > > > >>
> > > > > >> First, let me be clear that mixer0 and mixer1 don't have same
> > > > > >> capabilities
> > > > > >> (different number of planes, mixer0 supports writeback, mixer1
> > > > > >> does
> > > > > >> not,
> > > > > >> etc.). Thus, it does matter which mixer is connected to which
> > > > > >> TCON/encoder.
> > > > > >> mixer0 is meant to be connected to main display and mixer1 to
> > > > > >> auxiliary. That obviously depends on end system.
> > > > > >>
> > > > > >> So, TCON TOP has 3 muxes, which have to be represented in graph.
> > > > > >> Two of
> > > > > >> them are for mixer/TCON relationship (each of them 1 input and 4
> > > > > >> possible outputs) and one for TV TCON/HDMI pair selection (2
> > > > > >> possible
> > > > > >> inputs, 1 output).
> > > > > >>
> > > > > >> According to current practice in sun4i-drm driver, graph has to
> > > > > >> have
> > > > > >> port 0, representing input and port 1, representing output. This
> > > > > >> would
> > > > > >> mean that graph looks something like that:
> > > > > >>
> > > > > >> tcon_top: tcon-top@1c70000 {
> > > > > >>
> > > > > >> compatible = "allwinner,sun8i-r40-tcon-top";
> > > > > >> ...
> > > > > >> ports {
> > > > > >>
> > > > > >> #address-cells = <1>;
> > > > > >> #size-cells = <0>;
> > > > > >>
> > > > > >> tcon_top_in: port@0 {
> > > > > >>
> > > > > >> #address-cells = <1>;
> > > > > >> #size-cells = <0>;
> > > > > >> reg = <0>;
> > > > > >>
> > > > > >> tcon_top_in_mixer0: endpoint@0 {
> > > > > >>
> > > > > >> reg = <0>;
> > > > > >> remote-endpoint =
> > > > > >> <&mixer0_out_tcon_top>;
> > > > > >>
> > > > > >> };
> > > > > >>
> > > > > >> tcon_top_in_mixer1: endpoint@1 {
> > > > > >>
> > > > > >> reg = <1>;
> > > > > >> remote-endpoint =
> > > > > >> <&mixer1_out_tcon_top>;
> > > > > >>
> > > > > >> };
> > > > > >>
> > > > > >> tcon_top_in_tcon_tv: endpoint@2 {
> > > > > >>
> > > > > >> reg = <2>;
> > > > > >> // here is HDMI input connection,
> > > > > >> part of
> > > > > >> board DTS
> > > > > >> remote-endpoint = <board specific
> > > > > >> phandle
> > > > > >> to TV TCON output>;
> > > > > >>
> > > > > >> };
> > > > > >>
> > > > > >> };
> > > > > >>
> > > > > >> tcon_top_out: port@1 {
> > > > > >>
> > > > > >> #address-cells = <1>;
> > > > > >> #size-cells = <0>;
> > > > > >> reg = <1>;
> > > > > >>
> > > > > >> tcon_top_out_tcon0: endpoint@0 {
> > > > > >>
> > > > > >> reg = <0>;
> > > > > >> // here is mixer0 output
> > > > > >> connection,
> > > > > >> part
> > > > > >> of board DTS
> > > > > >> remote-endpoint = <board specific
> > > > > >> phandle
> > > > > >> to TCON>;
> > > > > >>
> > > > > >> };
> > > > > >>
> > > > > >> tcon_top_out_tcon1: endpoint@1 {
> > > > > >>
> > > > > >> reg = <1>;
> > > > > >> // here is mixer1 output
> > > > > >> connection,
> > > > > >> part
> > > > > >> of board DTS
> > > > > >> remote-endpoint = <board specific
> > > > > >> phandle
> > > > > >> to TCON>;
> > > > > >>
> > > > > >> };
> > > > > >>
> > > > > >> tcon_top_out_hdmi: endpoint@2 {
> > > > > >>
> > > > > >> reg = <2>;
> > > > > >> remote-endpoint =
> > > > > >> <&hdmi_in_tcon_top>;
> > > > > >>
> > > > > >> };
> > > > > >>
> > > > > >> };
> > > > > >>
> > > > > >> };
> > > > > >>
> > > > > >> };
> > > > > >
> > > > > > IIRC, each port is supposed to be one route for the data, so we
> > > > > > would
> > > > > > have multiple ports, one for the mixers in input and for the tcon
> > > > > > in
> > > > > > output, and one for the TCON in input and for the HDMI/TV in
> > > > > > output. Rob might correct me here.
> > >
> > > Ok, that seems more clean approach. I'll have to extend graph traversing
> > > algorithm in sun4i_drv.c, but that's no problem.
> > >
> > > Just to be clear, you have in mind 3 pairs of ports (0/1 for mixer0 mux,
> > > 2/3 for mixer1 and 4/5 for HDMI input), right? That way each mux is
> > > represented with one pair of ports, even numbered for input and odd
> > > numbered for output.
> >
> > Yep, unless Rob feels otherwise.
>
> I found an issue with this concept.
>
> HDMI driver (sun8i_dw_hdmi.c) uses drm_of_find_possible_crtcs() to find
> connected crtcs (TCONs) to HDMI. This function assumes that crtc and encoder
> are directly connected through of_graph, but that is not the case with TCON
> TOP HDMI mux anymore.
> I could give TCON TOP node as an input to this function, but that won't
> work, since TCON TOP can have connections to other crtcs, not only that of
> HDMI and they will also be picked up by drm_of_find_possible_crtcs().
>
> Any suggestion how to solve this nicely? I think creating my own version of
> drm_of_find_possible_crtcs() which considers that case is one way, but not
> very nice solution. Alternatively, we can fix possible_crtcs to BIT(0),

This doesn't seem like a good solution, since it doesn't work in dual head
system. I'll take first approach.

Best regards,
Jernej

> since it always has only one input. This is done in meson_dw_hdmi.c for
> example.