2018-03-01 21:36:33

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH v3 00/16] Implement H3/H5 HDMI driver

This series implements H3/H5 HDMI driver. It was tested on OrangePi 2 (H3),
OrangePi Plus2e (H3) and OrangePi PC2 (H5) with many resolutions and it
works well.

Code is based on linux-next, next-20180228 tag.

Best regards,
Jernej

Changes in v3:
- Removed TCON patch to skip LVDS procesing
- Added TCON patch to release exclusive clock lock
- Minimal clock rate is now returned immediately in round_rate for NM PLLs

Changes in v2:
- Fixed build warning on arm64
- Fixed condition in determine_rate function in HDMI PHY clock driver
- Added defines for polarity settings in HDMI PHY
- Added patch to skip LVDS code path altogether if TCON doesn't support it.
- round_rate for NM PLLs now rounds to minimal rate if requested rate is
lower.
- set_rate for NM PLLs doesn't fail if requested rate is lower than minimal
(round_rate is called before which already guarantees that rate is not
lower than minimal).

Jernej Skrabec (16):
clk: sunxi-ng: Add check for minimal rate to NM PLLs
clk: sunxi-ng: h3: h5: Add minimal rate for video PLL
clk: sunxi-ng: h3: h5: Allow some clocks to set parent rate
clk: sunxi-ng: h3: h5: export CLK_PLL_VIDEO
dt-bindings: display: sun4i-drm: Add compatibles for H3 HDMI pipeline
drm/sun4i: Release exclusive clock lock when disabling TCON
drm/sun4i: Add support for H3 display engine
drm/sun4i: Add support for H3 mixer 0
drm/sun4i: Fix polarity configuration for DW HDMI PHY
drm/sun4i: Add support for variants to DW HDMI PHY
drm/sun4i: Move and expand DW HDMI PHY register macros
drm/sun4i: Add support for H3 HDMI PHY variant
drm/sun4i: Allow building on arm64
ARM: dts: sunxi: h3/h5: Add HDMI pipeline
ARM: dts: sun8i: h3: Enable HDMI output on H3 boards
ARM64: dts: sun50i: h5: Enable HDMI output on H5 boards

.../bindings/display/sunxi/sun4i-drm.txt | 6 +
arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts | 25 ++
arch/arm/boot/dts/sun8i-h3-beelink-x2.dts | 25 ++
arch/arm/boot/dts/sun8i-h3-libretech-all-h3-cc.dts | 25 ++
arch/arm/boot/dts/sun8i-h3-nanopi-m1.dts | 25 ++
arch/arm/boot/dts/sun8i-h3-orangepi-2.dts | 25 ++
arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts | 25 ++
arch/arm/boot/dts/sun8i-h3-orangepi-one.dts | 24 ++
arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts | 25 ++
arch/arm/boot/dts/sunxi-h3-h5.dtsi | 108 ++++++
.../boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts | 25 ++
.../dts/allwinner/sun50i-h5-orangepi-prime.dts | 25 ++
.../allwinner/sun50i-h5-orangepi-zero-plus2.dts | 25 ++
drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 32 +-
drivers/clk/sunxi-ng/ccu-sun8i-h3.h | 4 +-
drivers/clk/sunxi-ng/ccu_nm.c | 7 +
drivers/clk/sunxi-ng/ccu_nm.h | 27 ++
drivers/gpu/drm/sun4i/Kconfig | 2 +-
drivers/gpu/drm/sun4i/Makefile | 1 +
drivers/gpu/drm/sun4i/sun4i_drv.c | 1 +
drivers/gpu/drm/sun4i/sun4i_tcon.c | 6 +-
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 157 ++++++++-
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 369 ++++++++++++++++++---
drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c | 132 ++++++++
drivers/gpu/drm/sun4i/sun8i_mixer.c | 12 +
include/dt-bindings/clock/sun8i-h3-ccu.h | 2 +
26 files changed, 1070 insertions(+), 70 deletions(-)
create mode 100644 drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c

--
2.16.2



2018-03-01 21:36:38

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH v3 16/16] ARM64: dts: sun50i: h5: Enable HDMI output on H5 boards

Enable HDMI output on all boards with HDMI connector.

Signed-off-by: Jernej Skrabec <[email protected]>
---
.../boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts | 25 ++++++++++++++++++++++
.../dts/allwinner/sun50i-h5-orangepi-prime.dts | 25 ++++++++++++++++++++++
.../allwinner/sun50i-h5-orangepi-zero-plus2.dts | 25 ++++++++++++++++++++++
3 files changed, 75 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts
index 58505fbc2667..98862c7c7258 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts
@@ -67,6 +67,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";

@@ -121,6 +132,10 @@
status = "okay";
};

+&de {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
@@ -153,6 +168,16 @@
};
};

+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
&ir {
pinctrl-names = "default";
pinctrl-0 = <&ir_pins_a>;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts
index 803566608ed8..b75ca4d7d001 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-prime.dts
@@ -62,6 +62,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";

@@ -128,6 +139,10 @@
status = "okay";
};

+&de {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
@@ -160,6 +175,16 @@
};
};

+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
&ir {
pinctrl-names = "default";
pinctrl-0 = <&ir_pins_a>;
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus2.dts
index eda24d813282..53c8c11620e0 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus2.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus2.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>;
+ };
+ };
+ };
+
reg_vcc3v3: vcc3v3 {
compatible = "regulator-fixed";
regulator-name = "vcc3v3";
@@ -73,6 +84,20 @@
};
};

+&de {
+ status = "okay";
+};
+
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
&mmc0 {
vmmc-supply = <&reg_vcc3v3>;
bus-width = <4>;
--
2.16.2


2018-03-01 21:36:40

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH v3 15/16] ARM: dts: sun8i: h3: Enable HDMI output on H3 boards

Enable HDMI output on all boards which have HDMI connector.

Signed-off-by: Jernej Skrabec <[email protected]>
---
arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts | 25 ++++++++++++++++++++++
arch/arm/boot/dts/sun8i-h3-beelink-x2.dts | 25 ++++++++++++++++++++++
arch/arm/boot/dts/sun8i-h3-libretech-all-h3-cc.dts | 25 ++++++++++++++++++++++
arch/arm/boot/dts/sun8i-h3-nanopi-m1.dts | 25 ++++++++++++++++++++++
arch/arm/boot/dts/sun8i-h3-orangepi-2.dts | 25 ++++++++++++++++++++++
arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts | 25 ++++++++++++++++++++++
arch/arm/boot/dts/sun8i-h3-orangepi-one.dts | 24 +++++++++++++++++++++
arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts | 25 ++++++++++++++++++++++
8 files changed, 199 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts b/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts
index 9c1bc472fb1c..30540dc8e0c5 100644
--- a/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts
+++ b/arch/arm/boot/dts/sun8i-h3-bananapi-m2-plus.dts
@@ -61,6 +61,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";
pinctrl-names = "default";
@@ -100,6 +111,10 @@
};
};

+&de {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
@@ -129,6 +144,16 @@
};
};

+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
&ir {
pinctrl-names = "default";
pinctrl-0 = <&ir_pins_a>;
diff --git a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts
index 870aabcbb2d8..cf1f970b0c6f 100644
--- a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts
+++ b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts
@@ -61,6 +61,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";

@@ -100,6 +111,10 @@
};
};

+&de {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
@@ -108,6 +123,16 @@
status = "okay";
};

+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
&ir {
pinctrl-names = "default";
pinctrl-0 = <&ir_pins_a>;
diff --git a/arch/arm/boot/dts/sun8i-h3-libretech-all-h3-cc.dts b/arch/arm/boot/dts/sun8i-h3-libretech-all-h3-cc.dts
index d0d41eb86cb4..b20a710da7bc 100644
--- a/arch/arm/boot/dts/sun8i-h3-libretech-all-h3-cc.dts
+++ b/arch/arm/boot/dts/sun8i-h3-libretech-all-h3-cc.dts
@@ -23,6 +23,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";

@@ -120,6 +131,10 @@
status = "okay";
};

+&de {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
@@ -143,6 +158,16 @@
status = "okay";
};

+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
&ir {
pinctrl-names = "default";
pinctrl-0 = <&ir_pins_a>;
diff --git a/arch/arm/boot/dts/sun8i-h3-nanopi-m1.dts b/arch/arm/boot/dts/sun8i-h3-nanopi-m1.dts
index c77fbca4f227..9412668bb888 100644
--- a/arch/arm/boot/dts/sun8i-h3-nanopi-m1.dts
+++ b/arch/arm/boot/dts/sun8i-h3-nanopi-m1.dts
@@ -49,6 +49,21 @@
aliases {
ethernet0 = &emac;
};
+
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+};
+
+&de {
+ status = "okay";
};

&ehci1 {
@@ -66,6 +81,16 @@
status = "okay";
};

+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
&ir {
pinctrl-names = "default";
pinctrl-0 = <&ir_pins_a>;
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts
index 7569bd05e249..f1fc6bdca8be 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts
@@ -62,6 +62,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";
pinctrl-names = "default";
@@ -114,6 +125,10 @@
status = "okay";
};

+&de {
+ status = "okay";
+};
+
&ehci1 {
status = "okay";
};
@@ -125,6 +140,16 @@
status = "okay";
};

+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
&ir {
pinctrl-names = "default";
pinctrl-0 = <&ir_pins_a>;
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts
index 2e59fd296717..476ae8e387ca 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-lite.dts
@@ -61,6 +61,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";
pinctrl-names = "default";
@@ -91,6 +102,10 @@
};
};

+&de {
+ status = "okay";
+};
+
&ehci1 {
status = "okay";
};
@@ -99,6 +114,16 @@
status = "okay";
};

+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
&ir {
pinctrl-names = "default";
pinctrl-0 = <&ir_pins_a>;
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
index c1a8cd93c463..3328fe583c9b 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
@@ -60,6 +60,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";
pinctrl-names = "default";
@@ -90,6 +101,10 @@
};
};

+&de {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
@@ -102,9 +117,18 @@
phy-handle = <&int_mii_phy>;
phy-mode = "mii";
allwinner,leds-active-low;
+};
+
+&hdmi {
status = "okay";
};

+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
&mmc0 {
vmmc-supply = <&reg_vcc3v3>;
bus-width = <4>;
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
index 537227b85935..cea4d647ecbf 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
@@ -60,6 +60,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";
pinctrl-names = "default";
@@ -98,6 +109,10 @@
status = "okay";
};

+&de {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
@@ -121,6 +136,16 @@
status = "okay";
};

+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
&ir {
pinctrl-names = "default";
pinctrl-0 = <&ir_pins_a>;
--
2.16.2


2018-03-01 21:37:44

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH v3 13/16] drm/sun4i: Allow building on arm64

64-bit ARM SoCs from Allwinner have DE2/TCON/HDMI periphery which
is compatible to 32-bit SoCs, so allow building DRM driver for
arm64 architecture.

Signed-off-by: Jernej Skrabec <[email protected]>
---
drivers/gpu/drm/sun4i/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
index 7327da3bc94f..eee6bc0eaf97 100644
--- a/drivers/gpu/drm/sun4i/Kconfig
+++ b/drivers/gpu/drm/sun4i/Kconfig
@@ -1,6 +1,6 @@
config DRM_SUN4I
tristate "DRM Support for Allwinner A10 Display Engine"
- depends on DRM && ARM && COMMON_CLK
+ depends on DRM && (ARM || ARM64) && COMMON_CLK
depends on ARCH_SUNXI || COMPILE_TEST
select DRM_GEM_CMA_HELPER
select DRM_KMS_HELPER
--
2.16.2


2018-03-01 21:38:00

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH v3 11/16] drm/sun4i: Move and expand DW HDMI PHY register macros

DW HDMI PHY macros are moved to header file and expanded with the
registers present on newer SoCs like H3 and H5.

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

diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
index 1e9eb6072615..49161326ea5a 100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
@@ -12,6 +12,137 @@
#include <linux/regmap.h>
#include <linux/reset.h>

+#define SUN8I_HDMI_PHY_DBG_CTRL_REG 0x0000
+#define SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK BIT(0)
+#define SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK GENMASK(15, 8)
+#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC BIT(8)
+#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC BIT(9)
+#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK GENMASK(23, 16)
+#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR(addr) (addr << 16)
+
+#define SUN8I_HDMI_PHY_REXT_CTRL_REG 0x0004
+#define SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN BIT(31)
+
+#define SUN8I_HDMI_PHY_READ_EN_REG 0x0010
+#define SUN8I_HDMI_PHY_READ_EN_MAGIC 0x54524545
+
+#define SUN8I_HDMI_PHY_UNSCRAMBLE_REG 0x0014
+#define SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC 0x42494E47
+
+#define SUN8I_HDMI_PHY_ANA_CFG1_REG 0x0020
+#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SWI BIT(31)
+#define SUN8I_HDMI_PHY_ANA_CFG1_REG_PWEND BIT(30)
+#define SUN8I_HDMI_PHY_ANA_CFG1_REG_PWENC BIT(29)
+#define SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW BIT(28)
+#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SVRCAL(x) ((x) << 26)
+#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SVBH(x) ((x) << 24)
+#define SUN8I_HDMI_PHY_ANA_CFG1_AMP_OPT BIT(23)
+#define SUN8I_HDMI_PHY_ANA_CFG1_EMP_OPT BIT(22)
+#define SUN8I_HDMI_PHY_ANA_CFG1_AMPCK_OPT BIT(21)
+#define SUN8I_HDMI_PHY_ANA_CFG1_EMPCK_OPT BIT(20)
+#define SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL BIT(19)
+#define SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG BIT(18)
+#define SUN8I_HDMI_PHY_ANA_CFG1_REG_SCKTMDS BIT(17)
+#define SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN BIT(16)
+#define SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK GENMASK(15, 12)
+#define SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL (0xf << 12)
+#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK BIT(11)
+#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 BIT(10)
+#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 BIT(9)
+#define SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 BIT(8)
+#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK BIT(7)
+#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2 BIT(6)
+#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 BIT(5)
+#define SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 BIT(4)
+#define SUN8I_HDMI_PHY_ANA_CFG1_CKEN BIT(3)
+#define SUN8I_HDMI_PHY_ANA_CFG1_LDOEN BIT(2)
+#define SUN8I_HDMI_PHY_ANA_CFG1_ENVBS BIT(1)
+#define SUN8I_HDMI_PHY_ANA_CFG1_ENBI BIT(0)
+
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG 0x0024
+#define SUN8I_HDMI_PHY_ANA_CFG2_M_EN BIT(31)
+#define SUN8I_HDMI_PHY_ANA_CFG2_PLLDBEN BIT(30)
+#define SUN8I_HDMI_PHY_ANA_CFG2_SEN BIT(29)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_HPDPD BIT(28)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_HPDEN BIT(27)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_PLRCK BIT(26)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_PLR(x) ((x) << 23)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_DENCK BIT(22)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_DEN BIT(21)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_CD(x) ((x) << 19)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_CKSS(x) ((x) << 17)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK BIT(16)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW BIT(15)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_CSMPS(x) ((x) << 13)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(x) ((x) << 10)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BOOSTCK(x) ((x) << 8)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_BOOST(x) ((x) << 6)
+#define SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(x) ((x) << 0)
+
+#define SUN8I_HDMI_PHY_ANA_CFG3_REG 0x0028
+#define SUN8I_HDMI_PHY_ANA_CFG3_REG_SLOWCK(x) ((x) << 30)
+#define SUN8I_HDMI_PHY_ANA_CFG3_REG_SLOW(x) ((x) << 28)
+#define SUN8I_HDMI_PHY_ANA_CFG3_REG_WIRE(x) ((x) << 18)
+#define SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(x) ((x) << 14)
+#define SUN8I_HDMI_PHY_ANA_CFG3_REG_EMPCK(x) ((x) << 11)
+#define SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(x) ((x) << 7)
+#define SUN8I_HDMI_PHY_ANA_CFG3_REG_EMP(x) ((x) << 4)
+#define SUN8I_HDMI_PHY_ANA_CFG3_SDAPD BIT(3)
+#define SUN8I_HDMI_PHY_ANA_CFG3_SDAEN BIT(2)
+#define SUN8I_HDMI_PHY_ANA_CFG3_SCLPD BIT(1)
+#define SUN8I_HDMI_PHY_ANA_CFG3_SCLEN BIT(0)
+
+#define SUN8I_HDMI_PHY_PLL_CFG1_REG 0x002c
+#define SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 BIT(31)
+#define SUN8I_HDMI_PHY_PLL_CFG1_REG_OD BIT(30)
+#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_PLLEN BIT(25)
+#define SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(x) ((x) << 22)
+#define SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(x) ((x) << 20)
+#define SUN8I_HDMI_PHY_PLL_CFG1_PLLDBEN BIT(19)
+#define SUN8I_HDMI_PHY_PLL_CFG1_CS BIT(18)
+#define SUN8I_HDMI_PHY_PLL_CFG1_CP_S(x) ((x) << 13)
+#define SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(x) ((x) << 7)
+#define SUN8I_HDMI_PHY_PLL_CFG1_BWS BIT(6)
+#define SUN8I_HDMI_PHY_PLL_CFG1_B_IN_MSK GENMASK(5, 0)
+#define SUN8I_HDMI_PHY_PLL_CFG1_B_IN_SHIFT 0
+
+#define SUN8I_HDMI_PHY_PLL_CFG2_REG 0x0030
+#define SUN8I_HDMI_PHY_PLL_CFG2_SV_H BIT(31)
+#define SUN8I_HDMI_PHY_PLL_CFG2_PDCLKSEL(x) ((x) << 29)
+#define SUN8I_HDMI_PHY_PLL_CFG2_CLKSTEP(x) ((x) << 27)
+#define SUN8I_HDMI_PHY_PLL_CFG2_PSET(x) ((x) << 24)
+#define SUN8I_HDMI_PHY_PLL_CFG2_PCLK_SEL BIT(23)
+#define SUN8I_HDMI_PHY_PLL_CFG2_AUTOSYNC_DIS BIT(22)
+#define SUN8I_HDMI_PHY_PLL_CFG2_VREG2_OUT_EN BIT(21)
+#define SUN8I_HDMI_PHY_PLL_CFG2_VREG1_OUT_EN BIT(20)
+#define SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN_EN BIT(19)
+#define SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN(x) ((x) << 16)
+#define SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(x) ((x) << 12)
+#define SUN8I_HDMI_PHY_PLL_CFG2_VCO_RST_IN BIT(11)
+#define SUN8I_HDMI_PHY_PLL_CFG2_SINT_FRAC BIT(10)
+#define SUN8I_HDMI_PHY_PLL_CFG2_SDIV2 BIT(9)
+#define SUN8I_HDMI_PHY_PLL_CFG2_S(x) ((x) << 6)
+#define SUN8I_HDMI_PHY_PLL_CFG2_S6P25_7P5 BIT(5)
+#define SUN8I_HDMI_PHY_PLL_CFG2_S5_7 BIT(4)
+#define SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK GENMASK(3, 0)
+#define SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_SHIFT 0
+#define SUN8I_HDMI_PHY_PLL_CFG2_PREDIV(x) (((x) - 1) << 0)
+
+#define SUN8I_HDMI_PHY_PLL_CFG3_REG 0x0034
+#define SUN8I_HDMI_PHY_PLL_CFG3_SOUT_DIV2 BIT(0)
+
+#define SUN8I_HDMI_PHY_ANA_STS_REG 0x0038
+#define SUN8I_HDMI_PHY_ANA_STS_B_OUT_SHIFT 11
+#define SUN8I_HDMI_PHY_ANA_STS_B_OUT_MSK GENMASK(16, 11)
+#define SUN8I_HDMI_PHY_ANA_STS_RCALEND2D BIT(7)
+#define SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK GENMASK(5, 0)
+
+#define SUN8I_HDMI_PHY_CEC_REG 0x003c
+
struct sun8i_hdmi_phy;

struct sun8i_hdmi_phy_variant {
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
index 17aada64bafd..16889bc0c62d 100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -7,23 +7,6 @@

#include "sun8i_dw_hdmi.h"

-#define SUN8I_HDMI_PHY_DBG_CTRL_REG 0x0000
-#define SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK BIT(0)
-#define SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK GENMASK(15, 8)
-#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC BIT(8)
-#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC BIT(9)
-#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK GENMASK(23, 16)
-#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR(addr) (addr << 16)
-
-#define SUN8I_HDMI_PHY_REXT_CTRL_REG 0x0004
-#define SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN BIT(31)
-
-#define SUN8I_HDMI_PHY_READ_EN_REG 0x0010
-#define SUN8I_HDMI_PHY_READ_EN_MAGIC 0x54524545
-
-#define SUN8I_HDMI_PHY_UNSCRAMBLE_REG 0x0014
-#define SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC 0x42494E47
-
/*
* Address can be actually any value. Here is set to same value as
* it is set in BSP driver.
--
2.16.2


2018-03-01 21:39:15

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH v3 14/16] ARM: dts: sunxi: h3/h5: Add HDMI pipeline

This commit adds all entries needed for HDMI to function properly.

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

diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
index 7741166d34d8..1be1a02d6df2 100644
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -105,6 +105,12 @@
};
};

+ de: display-engine {
+ compatible = "allwinner,sun8i-h3-display-engine";
+ allwinner,pipelines = <&mixer0>;
+ status = "disabled";
+ };
+
soc {
compatible = "simple-bus";
#address-cells = <1>;
@@ -123,6 +129,29 @@
#reset-cells = <1>;
};

+ mixer0: mixer@1100000 {
+ compatible = "allwinner,sun8i-h3-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>;
+
+ mixer0_out_tcon0: endpoint {
+ remote-endpoint = <&tcon0_in_mixer0>;
+ };
+ };
+ };
+ };
+
syscon: syscon@1c00000 {
compatible = "allwinner,sun8i-h3-system-controller",
"syscon";
@@ -138,6 +167,41 @@
#dma-cells = <1>;
};

+ tcon0: lcd-controller@1c0c000 {
+ compatible = "allwinner,sun8i-h3-tcon-tv",
+ "allwinner,sun8i-a83t-tcon-tv";
+ reg = <0x01c0c000 0x1000>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_TCON0>, <&ccu CLK_TCON0>;
+ clock-names = "ahb", "tcon-ch1";
+ resets = <&ccu RST_BUS_TCON0>;
+ reset-names = "lcd";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tcon0_in: port@0 {
+ reg = <0>;
+
+ tcon0_in_mixer0: endpoint {
+ remote-endpoint = <&mixer0_out_tcon0>;
+ };
+ };
+
+ tcon0_out: port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ tcon0_out_hdmi: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&hdmi_in_tcon0>;
+ };
+ };
+ };
+ };
+
mmc0: mmc@1c0f000 {
/* compatible and clocks are in per SoC .dtsi file */
reg = <0x01c0f000 0x1000>;
@@ -682,6 +746,50 @@
interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
};

+ hdmi: hdmi@1ee0000 {
+ compatible = "allwinner,sun8i-h3-dw-hdmi",
+ "allwinner,sun8i-a83t-dw-hdmi";
+ reg = <0x01ee0000 0x10000>;
+ reg-io-width = <1>;
+ interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI_DDC>,
+ <&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_in_tcon0: endpoint {
+ remote-endpoint = <&tcon0_out_hdmi>;
+ };
+ };
+
+ hdmi_out: port@1 {
+ reg = <1>;
+ };
+ };
+ };
+
+ hdmi_phy: hdmi-phy@1ef0000 {
+ compatible = "allwinner,sun8i-h3-hdmi-phy";
+ reg = <0x01ef0000 0x10000>;
+ clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI_DDC>,
+ <&ccu 6>;
+ clock-names = "bus", "mod", "pll-0";
+ resets = <&ccu RST_BUS_HDMI0>;
+ reset-names = "phy";
+ #phy-cells = <0>;
+ };
+
rtc: rtc@1f00000 {
compatible = "allwinner,sun6i-a31-rtc";
reg = <0x01f00000 0x54>;
--
2.16.2


2018-03-01 21:39:49

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH v3 12/16] drm/sun4i: Add support for H3 HDMI PHY variant

While A83T HDMI PHY seems to be just customized Synopsys HDMI PHY, H3
HDMI PHY is completely custom PHY.

However, they still have many things in common like clock and reset
setup, setting sync polarity and more.

Add support for H3 HDMI PHY variant.

While documentation exists for this PHY variant, it doesn't go in great
details. Because of that, almost all settings are copied from BSP linux
4.4. Interestingly, those settings are slightly different to those found
in a older BSP with Linux 3.4. For now, no user visible difference was
found between them.

Signed-off-by: Jernej Skrabec <[email protected]>
---
drivers/gpu/drm/sun4i/Makefile | 1 +
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 6 +
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 264 ++++++++++++++++++++++++++++-
drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c | 132 +++++++++++++++
4 files changed, 400 insertions(+), 3 deletions(-)
create mode 100644 drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c

diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 1610e748119b..330843ce4280 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -12,6 +12,7 @@ sun4i-drm-hdmi-y += sun4i_hdmi_tmds_clk.o

sun8i-drm-hdmi-y += sun8i_dw_hdmi.o
sun8i-drm-hdmi-y += sun8i_hdmi_phy.o
+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 \
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
index 49161326ea5a..79154f0f674a 100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
@@ -146,6 +146,7 @@
struct sun8i_hdmi_phy;

struct sun8i_hdmi_phy_variant {
+ bool has_phy_clk;
void (*phy_init)(struct sun8i_hdmi_phy *phy);
void (*phy_disable)(struct dw_hdmi *hdmi,
struct sun8i_hdmi_phy *phy);
@@ -157,6 +158,9 @@ struct sun8i_hdmi_phy_variant {
struct sun8i_hdmi_phy {
struct clk *clk_bus;
struct clk *clk_mod;
+ struct clk *clk_phy;
+ struct clk *clk_pll0;
+ unsigned int rcal;
struct regmap *regs;
struct reset_control *rst_phy;
struct sun8i_hdmi_phy_variant *variant;
@@ -184,4 +188,6 @@ 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);
+
#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 16889bc0c62d..5a52fc489a9d 100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -3,6 +3,7 @@
* Copyright (c) 2018 Jernej Skrabec <[email protected]>
*/

+#include <linux/delay.h>
#include <linux/of_address.h>

#include "sun8i_dw_hdmi.h"
@@ -73,7 +74,148 @@ static int sun8i_hdmi_phy_config_a83t(struct dw_hdmi *hdmi,
dw_hdmi_phy_gen2_txpwron(hdmi, 1);

return 0;
-};
+}
+
+static int sun8i_hdmi_phy_config_h3(struct dw_hdmi *hdmi,
+ struct sun8i_hdmi_phy *phy,
+ unsigned int clk_rate)
+{
+ u32 pll_cfg1_init;
+ u32 pll_cfg2_init;
+ u32 ana_cfg1_end;
+ u32 ana_cfg2_init;
+ u32 ana_cfg3_init;
+ u32 b_offset = 0;
+ u32 val;
+
+ /* bandwidth / frequency independent settings */
+
+ pll_cfg1_init = SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN |
+ SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN |
+ SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(7) |
+ SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(1) |
+ SUN8I_HDMI_PHY_PLL_CFG1_PLLDBEN |
+ SUN8I_HDMI_PHY_PLL_CFG1_CS |
+ SUN8I_HDMI_PHY_PLL_CFG1_CP_S(2) |
+ SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63) |
+ SUN8I_HDMI_PHY_PLL_CFG1_BWS;
+
+ pll_cfg2_init = SUN8I_HDMI_PHY_PLL_CFG2_SV_H |
+ SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN_EN |
+ SUN8I_HDMI_PHY_PLL_CFG2_SDIV2;
+
+ ana_cfg1_end = SUN8I_HDMI_PHY_ANA_CFG1_REG_SVBH(1) |
+ SUN8I_HDMI_PHY_ANA_CFG1_AMP_OPT |
+ SUN8I_HDMI_PHY_ANA_CFG1_EMP_OPT |
+ SUN8I_HDMI_PHY_ANA_CFG1_AMPCK_OPT |
+ SUN8I_HDMI_PHY_ANA_CFG1_EMPCK_OPT |
+ SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL |
+ SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG |
+ SUN8I_HDMI_PHY_ANA_CFG1_REG_SCKTMDS |
+ SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN |
+ SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK |
+ SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL |
+ SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK |
+ SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
+ SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
+ SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
+ SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2 |
+ SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
+ SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
+ SUN8I_HDMI_PHY_ANA_CFG1_CKEN |
+ SUN8I_HDMI_PHY_ANA_CFG1_LDOEN |
+ SUN8I_HDMI_PHY_ANA_CFG1_ENVBS |
+ SUN8I_HDMI_PHY_ANA_CFG1_ENBI;
+
+ ana_cfg2_init = SUN8I_HDMI_PHY_ANA_CFG2_M_EN |
+ SUN8I_HDMI_PHY_ANA_CFG2_REG_DENCK |
+ SUN8I_HDMI_PHY_ANA_CFG2_REG_DEN |
+ SUN8I_HDMI_PHY_ANA_CFG2_REG_CKSS(1) |
+ SUN8I_HDMI_PHY_ANA_CFG2_REG_CSMPS(1);
+
+ ana_cfg3_init = SUN8I_HDMI_PHY_ANA_CFG3_REG_WIRE(0x3e0) |
+ SUN8I_HDMI_PHY_ANA_CFG3_SDAEN |
+ SUN8I_HDMI_PHY_ANA_CFG3_SCLEN;
+
+ /* bandwidth / frequency dependent settings */
+ if (clk_rate <= 27000000) {
+ pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
+ SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
+ pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
+ SUN8I_HDMI_PHY_PLL_CFG2_S(4);
+ ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW;
+ ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) |
+ SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal);
+ ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(3) |
+ SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(5);
+ } else if (clk_rate <= 74250000) {
+ pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
+ SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
+ pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
+ SUN8I_HDMI_PHY_PLL_CFG2_S(5);
+ ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW;
+ ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) |
+ SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal);
+ ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(5) |
+ SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(7);
+ } else if (clk_rate <= 148500000) {
+ pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
+ SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
+ pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
+ SUN8I_HDMI_PHY_PLL_CFG2_S(6);
+ ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK |
+ SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW |
+ SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(2);
+ ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(7) |
+ SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(9);
+ } else {
+ b_offset = 2;
+ pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63);
+ pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(6) |
+ SUN8I_HDMI_PHY_PLL_CFG2_S(7);
+ ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK |
+ SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW |
+ SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4);
+ ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(9) |
+ SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(13);
+ }
+
+ 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);
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG,
+ (u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK,
+ pll_cfg2_init);
+ usleep_range(10000, 15000);
+ regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG3_REG,
+ SUN8I_HDMI_PHY_PLL_CFG3_SOUT_DIV2);
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
+ SUN8I_HDMI_PHY_PLL_CFG1_PLLEN,
+ SUN8I_HDMI_PHY_PLL_CFG1_PLLEN);
+ msleep(100);
+
+ /* get B value */
+ regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val);
+ val = (val & SUN8I_HDMI_PHY_ANA_STS_B_OUT_MSK) >>
+ SUN8I_HDMI_PHY_ANA_STS_B_OUT_SHIFT;
+ val = min(val + b_offset, (u32)0x3f);
+
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
+ SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 |
+ SUN8I_HDMI_PHY_PLL_CFG1_REG_OD,
+ SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 |
+ SUN8I_HDMI_PHY_PLL_CFG1_REG_OD);
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
+ SUN8I_HDMI_PHY_PLL_CFG1_B_IN_MSK,
+ val << SUN8I_HDMI_PHY_PLL_CFG1_B_IN_SHIFT);
+ msleep(100);
+ regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, ana_cfg1_end);
+ regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG2_REG, ana_cfg2_init);
+ regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG3_REG, ana_cfg3_init);
+
+ return 0;
+}

static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
struct drm_display_mode *mode)
@@ -90,6 +232,9 @@ static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK, val);

+ if (phy->variant->has_phy_clk)
+ clk_set_rate(phy->clk_phy, mode->crtc_clock * 1000);
+
return phy->variant->phy_config(hdmi, phy, mode->crtc_clock * 1000);
};

@@ -103,6 +248,16 @@ static void sun8i_hdmi_phy_disable_a83t(struct dw_hdmi *hdmi,
SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, 0);
}

+static void sun8i_hdmi_phy_disable_h3(struct dw_hdmi *hdmi,
+ struct sun8i_hdmi_phy *phy)
+{
+ regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
+ SUN8I_HDMI_PHY_ANA_CFG1_LDOEN |
+ SUN8I_HDMI_PHY_ANA_CFG1_ENVBS |
+ SUN8I_HDMI_PHY_ANA_CFG1_ENBI);
+ regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 0);
+}
+
static void sun8i_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
{
struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data;
@@ -133,6 +288,78 @@ static void sun8i_hdmi_phy_init_a83t(struct sun8i_hdmi_phy *phy)
SUN8I_HDMI_PHY_DBG_CTRL_ADDR(I2C_ADDR));
}

+static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
+{
+ unsigned int val;
+
+ regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 0);
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
+ SUN8I_HDMI_PHY_ANA_CFG1_ENBI,
+ SUN8I_HDMI_PHY_ANA_CFG1_ENBI);
+ udelay(5);
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
+ SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN,
+ SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN);
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
+ SUN8I_HDMI_PHY_ANA_CFG1_ENVBS,
+ SUN8I_HDMI_PHY_ANA_CFG1_ENVBS);
+ usleep_range(10, 20);
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
+ SUN8I_HDMI_PHY_ANA_CFG1_LDOEN,
+ SUN8I_HDMI_PHY_ANA_CFG1_LDOEN);
+ udelay(5);
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
+ SUN8I_HDMI_PHY_ANA_CFG1_CKEN,
+ SUN8I_HDMI_PHY_ANA_CFG1_CKEN);
+ usleep_range(40, 100);
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
+ SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL,
+ SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL);
+ usleep_range(100, 200);
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
+ SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG,
+ SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG);
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
+ SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
+ SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
+ SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2,
+ SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
+ SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
+ SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2);
+
+ /* wait for calibration to finish */
+ regmap_read_poll_timeout(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, val,
+ (val & SUN8I_HDMI_PHY_ANA_STS_RCALEND2D),
+ 100, 2000);
+
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
+ SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK,
+ SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK);
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
+ SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
+ SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
+ SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
+ SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK,
+ SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
+ SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
+ SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
+ SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK);
+
+ /* enable DDC communication */
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG3_REG,
+ SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
+ SUN8I_HDMI_PHY_ANA_CFG3_SDAEN,
+ SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
+ SUN8I_HDMI_PHY_ANA_CFG3_SDAEN);
+
+ /* set HW control of CEC pins */
+ regmap_write(phy->regs, SUN8I_HDMI_PHY_CEC_REG, 0);
+
+ /* read calibration data */
+ regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val);
+ phy->rcal = (val & SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK) >> 2;
+}
+
void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
{
/* enable read access to HDMI controller */
@@ -155,7 +382,7 @@ static struct regmap_config sun8i_hdmi_phy_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
- .max_register = SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
+ .max_register = SUN8I_HDMI_PHY_CEC_REG,
.name = "phy"
};

@@ -165,11 +392,22 @@ static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = {
.phy_config = &sun8i_hdmi_phy_config_a83t,
};

+static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = {
+ .has_phy_clk = 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 of_device_id sun8i_hdmi_phy_of_table[] = {
{
.compatible = "allwinner,sun8i-a83t-hdmi-phy",
.data = &sun8i_a83t_hdmi_phy,
},
+ {
+ .compatible = "allwinner,sun8i-h3-hdmi-phy",
+ .data = &sun8i_h3_hdmi_phy,
+ },
{ /* sentinel */ }
};

@@ -226,11 +464,26 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
goto err_put_clk_bus;
}

+ if (phy->variant->has_phy_clk) {
+ phy->clk_pll0 = of_clk_get_by_name(node, "pll-0");
+ if (IS_ERR(phy->clk_pll0)) {
+ dev_err(dev, "Could not get pll-0 clock\n");
+ ret = PTR_ERR(phy->clk_pll0);
+ goto err_put_clk_mod;
+ }
+
+ ret = sun8i_phy_clk_create(phy, dev);
+ if (ret) {
+ dev_err(dev, "Couldn't create the PHY clock\n");
+ goto err_put_clk_pll0;
+ }
+ }
+
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_mod;
+ goto err_put_clk_pll0;
}

ret = reset_control_deassert(phy->rst_phy);
@@ -261,6 +514,9 @@ 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_pll0:
+ if (phy->variant->has_phy_clk)
+ clk_put(phy->clk_pll0);
err_put_clk_mod:
clk_put(phy->clk_mod);
err_put_clk_bus:
@@ -280,6 +536,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_mod);
clk_put(phy->clk_bus);
}
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c
new file mode 100644
index 000000000000..faea449812f8
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Jernej Skrabec <[email protected]>
+ */
+
+#include <linux/clk-provider.h>
+
+#include "sun8i_dw_hdmi.h"
+
+struct sun8i_phy_clk {
+ struct clk_hw hw;
+ struct sun8i_hdmi_phy *phy;
+};
+
+static inline struct sun8i_phy_clk *hw_to_phy_clk(struct clk_hw *hw)
+{
+ return container_of(hw, struct sun8i_phy_clk, hw);
+}
+
+static int sun8i_phy_clk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ unsigned long rate = req->rate;
+ unsigned long best_rate = 0;
+ struct clk_hw *parent;
+ int best_div = 1;
+ int i;
+
+ 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);
+
+ if (rounded == ideal) {
+ best_rate = rounded;
+ best_div = i;
+ break;
+ }
+
+ if (!best_rate ||
+ abs(rate - rounded / i) <
+ abs(rate - best_rate / best_div)) {
+ best_rate = rounded;
+ best_div = i;
+ }
+ }
+
+ req->rate = best_rate / best_div;
+ req->best_parent_rate = best_rate;
+ req->best_parent_hw = parent;
+
+ return 0;
+}
+
+static unsigned long sun8i_phy_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct sun8i_phy_clk *priv = hw_to_phy_clk(hw);
+ u32 reg;
+
+ regmap_read(priv->phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG, &reg);
+ reg = ((reg >> SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_SHIFT) &
+ SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK) + 1;
+
+ return parent_rate / reg;
+}
+
+static int sun8i_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct sun8i_phy_clk *priv = hw_to_phy_clk(hw);
+ unsigned long best_rate = 0;
+ u8 best_m = 0, m;
+
+ for (m = 1; m <= 16; m++) {
+ unsigned long tmp_rate = parent_rate / m;
+
+ if (tmp_rate > rate)
+ continue;
+
+ if (!best_rate ||
+ (rate - tmp_rate) < (rate - best_rate)) {
+ best_rate = tmp_rate;
+ best_m = m;
+ }
+ }
+
+ regmap_update_bits(priv->phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG,
+ SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK,
+ SUN8I_HDMI_PHY_PLL_CFG2_PREDIV(best_m));
+
+ 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,
+};
+
+int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev)
+{
+ struct clk_init_data init;
+ struct sun8i_phy_clk *priv;
+ const char *parents[1];
+
+ parents[0] = __clk_get_name(phy->clk_pll0);
+ if (!parents[0])
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ init.name = "hdmi-phy-clk";
+ init.ops = &sun8i_phy_clk_ops;
+ init.parent_names = parents;
+ init.num_parents = 1;
+ init.flags = CLK_SET_RATE_PARENT;
+
+ priv->phy = phy;
+ priv->hw.init = &init;
+
+ phy->clk_phy = devm_clk_register(dev, &priv->hw);
+ if (IS_ERR(phy->clk_phy))
+ return PTR_ERR(phy->clk_phy);
+
+ return 0;
+}
--
2.16.2


2018-03-01 21:40:05

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH v3 09/16] drm/sun4i: Fix polarity configuration for DW HDMI PHY

Current polarity configuration code is cleary wrong since it compares
same flag two times. However, even if flag name is fixed, it won't work
well for resolutions which have one polarity positive and another
negative.

Fix that by properly set each bit according to each polarity. Since
those two bits are not described in any documentation, relationships
were obtained by experimentation.

Fixes: b7c7436a5ff0 ("drm/sun4i: Implement A83T HDMI driver")

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

diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
index e5bfcdd43ec9..9d2f11ca3538 100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -10,7 +10,8 @@
#define SUN8I_HDMI_PHY_DBG_CTRL_REG 0x0000
#define SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK BIT(0)
#define SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK GENMASK(15, 8)
-#define SUN8I_HDMI_PHY_DBG_CTRL_POL(val) (val << 8)
+#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC BIT(8)
+#define SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC BIT(9)
#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK GENMASK(23, 16)
#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR(addr) (addr << 16)

@@ -35,14 +36,14 @@ static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data;
u32 val = 0;

- if ((mode->flags & DRM_MODE_FLAG_NHSYNC) &&
- (mode->flags & DRM_MODE_FLAG_NHSYNC)) {
- val = 0x03;
- }
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC;
+
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC;

regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
- SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK,
- SUN8I_HDMI_PHY_DBG_CTRL_POL(val));
+ SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK, val);

regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN,
--
2.16.2


2018-03-01 21:40:21

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH v3 10/16] drm/sun4i: Add support for variants to DW HDMI PHY

There are multiple variants of DW HDMI PHYs in Allwinner SoCs. While
some things like clock and reset setup are the same, PHY configuration
differs a lot.

Split out code which is PHY specific to separate functions and create
a structure which holds pointers to those functions.

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

diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
index d8d0684fc8aa..1e9eb6072615 100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
@@ -12,11 +12,23 @@
#include <linux/regmap.h>
#include <linux/reset.h>

+struct sun8i_hdmi_phy;
+
+struct sun8i_hdmi_phy_variant {
+ void (*phy_init)(struct sun8i_hdmi_phy *phy);
+ void (*phy_disable)(struct dw_hdmi *hdmi,
+ struct sun8i_hdmi_phy *phy);
+ int (*phy_config)(struct dw_hdmi *hdmi,
+ struct sun8i_hdmi_phy *phy,
+ unsigned int clk_rate);
+};
+
struct sun8i_hdmi_phy {
- struct clk *clk_bus;
- struct clk *clk_mod;
- struct regmap *regs;
- struct reset_control *rst_phy;
+ struct clk *clk_bus;
+ struct clk *clk_mod;
+ struct regmap *regs;
+ struct reset_control *rst_phy;
+ struct sun8i_hdmi_phy_variant *variant;
};

struct sun8i_dw_hdmi {
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
index 9d2f11ca3538..17aada64bafd 100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -30,21 +30,10 @@
*/
#define I2C_ADDR 0x69

-static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
- struct drm_display_mode *mode)
+static int sun8i_hdmi_phy_config_a83t(struct dw_hdmi *hdmi,
+ struct sun8i_hdmi_phy *phy,
+ unsigned int clk_rate)
{
- struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data;
- u32 val = 0;
-
- if (mode->flags & DRM_MODE_FLAG_NHSYNC)
- val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC;
-
- if (mode->flags & DRM_MODE_FLAG_NVSYNC)
- val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC;
-
- regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
- SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK, val);
-
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN,
SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN);
@@ -64,21 +53,21 @@ static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
* release any documentation, explanation of this values can
* be found in i.MX 6Dual/6Quad Reference Manual.
*/
- if (mode->crtc_clock <= 27000) {
+ if (clk_rate <= 27000000) {
dw_hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
dw_hdmi_phy_i2c_write(hdmi, 0x08da, 0x10);
dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
dw_hdmi_phy_i2c_write(hdmi, 0x0318, 0x0e);
dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
- } else if (mode->crtc_clock <= 74250) {
+ } else if (clk_rate <= 74250000) {
dw_hdmi_phy_i2c_write(hdmi, 0x0540, 0x06);
dw_hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
dw_hdmi_phy_i2c_write(hdmi, 0x02b5, 0x0e);
dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
- } else if (mode->crtc_clock <= 148500) {
+ } else if (clk_rate <= 148500000) {
dw_hdmi_phy_i2c_write(hdmi, 0x04a0, 0x06);
dw_hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
@@ -103,10 +92,27 @@ static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
return 0;
};

-static void sun8i_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
+static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
+ struct drm_display_mode *mode)
{
struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data;
+ u32 val = 0;
+
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC;

+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC;
+
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
+ SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK, val);
+
+ return phy->variant->phy_config(hdmi, phy, mode->crtc_clock * 1000);
+};
+
+static void sun8i_hdmi_phy_disable_a83t(struct dw_hdmi *hdmi,
+ struct sun8i_hdmi_phy *phy)
+{
dw_hdmi_phy_gen2_txpwron(hdmi, 0);
dw_hdmi_phy_gen2_pddq(hdmi, 1);

@@ -114,6 +120,13 @@ static void sun8i_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, 0);
}

+static void sun8i_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
+{
+ struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data;
+
+ phy->variant->phy_disable(hdmi, phy);
+}
+
static const struct dw_hdmi_phy_ops sun8i_hdmi_phy_ops = {
.init = &sun8i_hdmi_phy_config,
.disable = &sun8i_hdmi_phy_disable,
@@ -122,16 +135,8 @@ static const struct dw_hdmi_phy_ops sun8i_hdmi_phy_ops = {
.setup_hpd = &dw_hdmi_phy_setup_hpd,
};

-void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
+static void sun8i_hdmi_phy_init_a83t(struct sun8i_hdmi_phy *phy)
{
- /* enable read access to HDMI controller */
- regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG,
- SUN8I_HDMI_PHY_READ_EN_MAGIC);
-
- /* unscramble register offsets */
- regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
- SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC);
-
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK,
SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK);
@@ -145,6 +150,19 @@ void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
SUN8I_HDMI_PHY_DBG_CTRL_ADDR(I2C_ADDR));
}

+void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
+{
+ /* enable read access to HDMI controller */
+ regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG,
+ SUN8I_HDMI_PHY_READ_EN_MAGIC);
+
+ /* unscramble register offsets */
+ regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
+ SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC);
+
+ phy->variant->phy_init(phy);
+}
+
const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void)
{
return &sun8i_hdmi_phy_ops;
@@ -158,20 +176,31 @@ static struct regmap_config sun8i_hdmi_phy_regmap_config = {
.name = "phy"
};

+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,
+ .phy_config = &sun8i_hdmi_phy_config_a83t,
+};
+
static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
- { .compatible = "allwinner,sun8i-a83t-hdmi-phy" },
+ {
+ .compatible = "allwinner,sun8i-a83t-hdmi-phy",
+ .data = &sun8i_a83t_hdmi_phy,
+ },
{ /* sentinel */ }
};

int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
{
+ const struct of_device_id *match;
struct device *dev = hdmi->dev;
struct sun8i_hdmi_phy *phy;
struct resource res;
void __iomem *regs;
int ret;

- if (!of_match_node(sun8i_hdmi_phy_of_table, node)) {
+ match = of_match_node(sun8i_hdmi_phy_of_table, node);
+ if (!match) {
dev_err(dev, "Incompatible HDMI PHY\n");
return -EINVAL;
}
@@ -180,6 +209,8 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
if (!phy)
return -ENOMEM;

+ phy->variant = (struct sun8i_hdmi_phy_variant *)match->data;
+
ret = of_address_to_resource(node, 0, &res);
if (ret) {
dev_err(dev, "phy: Couldn't get our resources\n");
--
2.16.2


2018-03-01 21:40:57

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH v3 06/16] drm/sun4i: Release exclusive clock lock when disabling TCON

Currently exclusive TCON clock lock is never released, which, for
example, prevents changing resolution on HDMI.

In order to fix that, release clock when disabling TCON. TCON is always
disabled first before new mode is set.

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

diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index 1d714c06ec9d..7f6c4125c89f 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -102,10 +102,12 @@ static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
return;
}

- if (enabled)
+ if (enabled) {
clk_prepare_enable(clk);
- else
+ } else {
+ clk_rate_exclusive_put(clk);
clk_disable_unprepare(clk);
+ }
}

static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon,
--
2.16.2


2018-03-01 21:41:13

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH v3 07/16] drm/sun4i: Add support for H3 display engine

H3 display engine has two mixers which are connected to HDMI and TV
output.

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

diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 3957c2ff6870..a0f43b81c64c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -359,6 +359,7 @@ static const struct of_device_id sun4i_drv_of_table[] = {
{ .compatible = "allwinner,sun7i-a20-display-engine" },
{ .compatible = "allwinner,sun8i-a33-display-engine" },
{ .compatible = "allwinner,sun8i-a83t-display-engine" },
+ { .compatible = "allwinner,sun8i-h3-display-engine" },
{ .compatible = "allwinner,sun8i-v3s-display-engine" },
{ }
};
--
2.16.2


2018-03-01 21:41:47

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH v3 05/16] dt-bindings: display: sun4i-drm: Add compatibles for H3 HDMI pipeline

Add missing compatibles for H3 HDMI pipeline. These compatibles can also
be used with H5 SoC.

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

diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
index b995bfee734a..8bdef4920edc 100644
--- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
+++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
@@ -102,6 +102,7 @@ DWC HDMI PHY
Required properties:
- compatible: value must be one of:
* allwinner,sun8i-a83t-hdmi-phy
+ * allwinner,sun8i-h3-hdmi-phy
- reg: base address and size of memory-mapped region
- clocks: phandles to the clocks feeding the HDMI PHY
* bus: the HDMI PHY interface clock
@@ -110,6 +111,9 @@ Required properties:
- resets: phandle to the reset controller driving the PHY
- reset-names: must be "phy"

+H3 HDMI PHY requires additional clock:
+ - pll-0: parent of phy clock
+
TV Encoder
----------

@@ -275,6 +279,7 @@ Required properties:
- compatible: value must be one of:
* allwinner,sun8i-a83t-de2-mixer-0
* allwinner,sun8i-a83t-de2-mixer-1
+ * allwinner,sun8i-h3-de2-mixer-0
* allwinner,sun8i-v3s-de2-mixer
- reg: base address and size of the memory-mapped region.
- clocks: phandles to the clocks feeding the mixer
@@ -305,6 +310,7 @@ Required properties:
* allwinner,sun7i-a20-display-engine
* allwinner,sun8i-a33-display-engine
* allwinner,sun8i-a83t-display-engine
+ * allwinner,sun8i-h3-display-engine
* allwinner,sun8i-v3s-display-engine

- allwinner,pipelines: list of phandle to the display engine
--
2.16.2


2018-03-01 21:42:00

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH v3 03/16] clk: sunxi-ng: h3: h5: Allow some clocks to set parent rate

Some units have to be able to set it's own clock precisely to work
correctly. Allow them to do so by adding CLK_SET_RATE_PARENT flag.

Add this flag to DE, TCON and HDMI clocks.

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

diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
index b9f39078c0b2..77ed0b0ba681 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
@@ -452,11 +452,13 @@ static SUNXI_CCU_GATE(dram_ts_clk, "dram-ts", "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 const char * const tcon_parents[] = { "pll-video" };
static SUNXI_CCU_M_WITH_MUX_GATE(tcon_clk, "tcon", tcon_parents,
- 0x118, 0, 4, 24, 3, BIT(31), 0);
+ 0x118, 0, 4, 24, 3, BIT(31),
+ CLK_SET_RATE_PARENT);

static const char * const tve_parents[] = { "pll-de", "pll-periph1" };
static SUNXI_CCU_M_WITH_MUX_GATE(tve_clk, "tve", tve_parents,
@@ -487,7 +489,8 @@ static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M",

static const char * const hdmi_parents[] = { "pll-video" };
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_ddc_clk, "hdmi-ddc", "osc24M",
0x154, BIT(31), 0);
--
2.16.2


2018-03-01 21:42:34

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH v3 01/16] clk: sunxi-ng: Add check for minimal rate to NM PLLs

Some NM PLLs doesn't work well when their output clock rate is set below
certain rate.

Add support for that constrain.

Signed-off-by: Jernej Skrabec <[email protected]>
---
drivers/clk/sunxi-ng/ccu_nm.c | 7 +++++++
drivers/clk/sunxi-ng/ccu_nm.h | 27 +++++++++++++++++++++++++++
2 files changed, 34 insertions(+)

diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c
index a16de092bf94..4e2073307f34 100644
--- a/drivers/clk/sunxi-ng/ccu_nm.c
+++ b/drivers/clk/sunxi-ng/ccu_nm.c
@@ -117,6 +117,13 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
rate *= nm->fixed_post_div;

+ if (rate < nm->min_rate) {
+ rate = nm->min_rate;
+ if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
+ rate /= nm->fixed_post_div;
+ return rate;
+ }
+
if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) {
if (nm->common.features & CCU_FEATURE_FIXED_POSTDIV)
rate /= nm->fixed_post_div;
diff --git a/drivers/clk/sunxi-ng/ccu_nm.h b/drivers/clk/sunxi-ng/ccu_nm.h
index eba586b4c7d0..1d8b459c50b7 100644
--- a/drivers/clk/sunxi-ng/ccu_nm.h
+++ b/drivers/clk/sunxi-ng/ccu_nm.h
@@ -37,6 +37,7 @@ struct ccu_nm {
struct ccu_sdm_internal sdm;

unsigned int fixed_post_div;
+ unsigned int min_rate;

struct ccu_common common;
};
@@ -88,6 +89,32 @@ struct ccu_nm {
}, \
}

+#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK_MIN(_struct, _name, _parent, \
+ _reg, _min_rate, \
+ _nshift, _nwidth, \
+ _mshift, _mwidth, \
+ _frac_en, _frac_sel, \
+ _frac_rate_0, _frac_rate_1,\
+ _gate, _lock, _flags) \
+ struct ccu_nm _struct = { \
+ .enable = _gate, \
+ .lock = _lock, \
+ .n = _SUNXI_CCU_MULT(_nshift, _nwidth), \
+ .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
+ .frac = _SUNXI_CCU_FRAC(_frac_en, _frac_sel, \
+ _frac_rate_0, \
+ _frac_rate_1), \
+ .min_rate = _min_rate, \
+ .common = { \
+ .reg = _reg, \
+ .features = CCU_FEATURE_FRACTIONAL, \
+ .hw.init = CLK_HW_INIT(_name, \
+ _parent, \
+ &ccu_nm_ops, \
+ _flags), \
+ }, \
+ }
+
#define SUNXI_CCU_NM_WITH_GATE_LOCK(_struct, _name, _parent, _reg, \
_nshift, _nwidth, \
_mshift, _mwidth, \
--
2.16.2


2018-03-01 21:42:51

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH v3 08/16] drm/sun4i: Add support for H3 mixer 0

This mixer supports 1 VI plane, 3 UI plane and HW scaling on all planes.

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

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 9b0256d31a61..126899d6f0d3 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -492,6 +492,14 @@ static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = {
.vi_num = 1,
};

+static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
+ .ccsc = 0,
+ .mod_rate = 432000000,
+ .scaler_mask = 0xf,
+ .ui_num = 3,
+ .vi_num = 1,
+};
+
static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
.vi_num = 2,
.ui_num = 1,
@@ -509,6 +517,10 @@ static const struct of_device_id sun8i_mixer_of_table[] = {
.compatible = "allwinner,sun8i-a83t-de2-mixer-1",
.data = &sun8i_a83t_mixer1_cfg,
},
+ {
+ .compatible = "allwinner,sun8i-h3-de2-mixer-0",
+ .data = &sun8i_h3_mixer0_cfg,
+ },
{
.compatible = "allwinner,sun8i-v3s-de2-mixer",
.data = &sun8i_v3s_mixer_cfg,
--
2.16.2


2018-03-01 22:12:29

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH v3 02/16] clk: sunxi-ng: h3: h5: Add minimal rate for video PLL

Although user manuals for H3 and H5 SoCs state that minimal rate
supported by video PLL is around 30 MHz, it seems that in reality
minimal rate is around 192 MHz.

Experiments showed that any rate below 96 MHz doesn't produce any video
output at all. Even at this frequency, stable output depends on right
factors. For example, when N = 4 and M = 1, output is stable and when N
= 8 and M = 2, it's not.

BSP clock driver suggest that minimum stable frequency is 192 MHz. That
would also be in line with A64 SoC, which has similar periphery.

Set minimal video PLL rate for H3/H5 to 192 MHz.

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

diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
index 29bc0566b776..b9f39078c0b2 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
@@ -69,17 +69,18 @@ static SUNXI_CCU_NM_WITH_SDM_GATE_LOCK(pll_audio_base_clk, "pll-audio-base",
BIT(28), /* lock */
CLK_SET_RATE_UNGATE);

-static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video_clk, "pll-video",
- "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_video_clk, "pll-video",
+ "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);

static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve",
"osc24M", 0x0018,
--
2.16.2


2018-03-01 22:12:40

by Jernej Skrabec

[permalink] [raw]
Subject: [PATCH v3 04/16] clk: sunxi-ng: h3: h5: export CLK_PLL_VIDEO

CLK_PLL_VIDEO needs to be referenced in HDMI DT entry as a possible
PHY clock parent.

Export it so it can be used later in DT.

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

diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.h b/drivers/clk/sunxi-ng/ccu-sun8i-h3.h
index 1b4baea37d81..73d7392c968c 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.h
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.h
@@ -26,7 +26,9 @@
#define CLK_PLL_AUDIO_2X 3
#define CLK_PLL_AUDIO_4X 4
#define CLK_PLL_AUDIO_8X 5
-#define CLK_PLL_VIDEO 6
+
+/* PLL_VIDEO is exported */
+
#define CLK_PLL_VE 7
#define CLK_PLL_DDR 8

diff --git a/include/dt-bindings/clock/sun8i-h3-ccu.h b/include/dt-bindings/clock/sun8i-h3-ccu.h
index e139fe5c62ec..c5f7e9a70968 100644
--- a/include/dt-bindings/clock/sun8i-h3-ccu.h
+++ b/include/dt-bindings/clock/sun8i-h3-ccu.h
@@ -43,6 +43,8 @@
#ifndef _DT_BINDINGS_CLK_SUN8I_H3_H_
#define _DT_BINDINGS_CLK_SUN8I_H3_H_

+#define CLK_PLL_VIDEO 6
+
#define CLK_PLL_PERIPH0 9

#define CLK_CPUX 14
--
2.16.2


2018-03-02 09:40:45

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v3 00/16] Implement H3/H5 HDMI driver

On Thu, Mar 01, 2018 at 10:34:26PM +0100, Jernej Skrabec wrote:
> This series implements H3/H5 HDMI driver. It was tested on OrangePi 2 (H3),
> OrangePi Plus2e (H3) and OrangePi PC2 (H5) with many resolutions and it
> works well.
>
> Code is based on linux-next, next-20180228 tag.

Applied everything, thanks!
Maxime

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


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

2018-03-05 15:34:39

by Joonas Kylmälä

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH v3 15/16] ARM: dts: sun8i: h3: Enable HDMI output on H3 boards

Jernej Skrabec:
> +&hdmi_out {
> + hdmi_out_con: endpoint {
> + remote-endpoint = <&hdmi_con_in>;
> + };
> +};

This node is added to all the DTS files you enabled HDMI on. Is it
something that could be instead put to the DTSI file?

Joonas

2018-03-05 18:35:03

by Jernej Skrabec

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH v3 15/16] ARM: dts: sun8i: h3: Enable HDMI output on H3 boards

Hi!

Dne ponedeljek, 05. marec 2018 ob 16:27:00 CET je Joonas Kylm?l? napisal(a):
> Jernej Skrabec:
> > +&hdmi_out {
> > + hdmi_out_con: endpoint {
> > + remote-endpoint = <&hdmi_con_in>;
> > + };
> > +};
>
> This node is added to all the DTS files you enabled HDMI on. Is it
> something that could be instead put to the DTSI file?

I guess that would mean also including connector node (hdmi_con_in) in DTSI,
since it is referenced inside. However, not all boards have HDMI connector, so
I didn't include it in DTSI.

Best regards,
Jernej



2018-03-05 20:44:58

by Joonas Kylmälä

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH v3 15/16] ARM: dts: sun8i: h3: Enable HDMI output on H3 boards

Jernej Škrabec:
> I guess that would mean also including connector node (hdmi_con_in) in DTSI,
> since it is referenced inside. However, not all boards have HDMI connector, so
> I didn't include it in DTSI.

You're absolutely right on this. I wish there was someway to get rid of
this duplication but that's a whole different problem to discuss.

Great work by the way!

Joonas

2018-03-07 19:37:38

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v3 04/16] clk: sunxi-ng: h3: h5: export CLK_PLL_VIDEO

On Thu, Mar 01, 2018 at 10:34:30PM +0100, Jernej Skrabec wrote:
> CLK_PLL_VIDEO needs to be referenced in HDMI DT entry as a possible
> PHY clock parent.
>
> Export it so it can be used later in DT.
>
> Signed-off-by: Jernej Skrabec <[email protected]>
> ---
> drivers/clk/sunxi-ng/ccu-sun8i-h3.h | 4 +++-
> include/dt-bindings/clock/sun8i-h3-ccu.h | 2 ++
> 2 files changed, 5 insertions(+), 1 deletion(-)

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


2018-03-07 19:39:17

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v3 05/16] dt-bindings: display: sun4i-drm: Add compatibles for H3 HDMI pipeline

On Thu, Mar 01, 2018 at 10:34:31PM +0100, Jernej Skrabec wrote:
> Add missing compatibles for H3 HDMI pipeline. These compatibles can also
> be used with H5 SoC.
>
> Signed-off-by: Jernej Skrabec <[email protected]>
> ---
> Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt | 6 ++++++
> 1 file changed, 6 insertions(+)

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


2018-03-08 22:58:40

by Ondřej Jirman

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH v3 06/16] drm/sun4i: Release exclusive clock lock when disabling TCON

Hi,

On Thu, Mar 01, 2018 at 10:34:32PM +0100, Jernej Skrabec wrote:
> Currently exclusive TCON clock lock is never released, which, for
> example, prevents changing resolution on HDMI.
>
> In order to fix that, release clock when disabling TCON. TCON is always
> disabled first before new mode is set.
>
> Signed-off-by: Jernej Skrabec <[email protected]>
> ---
> drivers/gpu/drm/sun4i/sun4i_tcon.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index 1d714c06ec9d..7f6c4125c89f 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -102,10 +102,12 @@ static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
> return;
> }
>
> - if (enabled)
> + if (enabled) {
> clk_prepare_enable(clk);
> - else
> + } else {
> + clk_rate_exclusive_put(clk);
> clk_disable_unprepare(clk);
> + }
> }

At least in the linux-next/master I can't see clk_rate_exclusive_get call:

$ git grep 'exclusive' linux-next/master -- drivers/gpu/drm/sun4i

linux-next/master:sun4i_hdmi.h: * On sun5i the threshold is exclusive, i.e. does not include,
linux-next/master:sun4i_tcon.c: clk_rate_exclusive_put(clk);
linux-next/master:sun4i_tcon.c: clk_set_rate_exclusive(tcon->dclk, mode->crtc_clock * 1000);
linux-next/master:sun4i_tcon.c: clk_set_rate_exclusive(tcon->sclk1, mode->crtc_clock * 1000);

and the kernel complains too:

[ 841.915161] ------------[ cut here ]------------
[ 841.915187] WARNING: CPU: 0 PID: 273 at /workspace/megous.com/orangepi-pc/linux-4.16/drivers/clk/clk.c:608 clk_rate_exclusive_put+0x48/0x4c
[ 841.915194] CPU: 0 PID: 273 Comm: Xorg Not tainted 4.16.0-rc4-00268-gbac2ecf73ed0 #13
[ 841.915196] Hardware name: Allwinner sun8i Family
[ 841.915217] [<c0228440>] (unwind_backtrace) from [<c0225b90>] (show_stack+0x10/0x14)
[ 841.915228] [<c0225b90>] (show_stack) from [<c0b094bc>] (dump_stack+0x88/0x9c)
[ 841.915237] [<c0b094bc>] (dump_stack) from [<c0240294>] (__warn+0xd4/0xf0)
[ 841.915244] [<c0240294>] (__warn) from [<c0240380>] (warn_slowpath_null+0x40/0x48)
[ 841.915250] [<c0240380>] (warn_slowpath_null) from [<c0619b6c>] (clk_rate_exclusive_put+0x48/0x4c)
[ 841.915261] [<c0619b6c>] (clk_rate_exclusive_put) from [<c0694624>] (sun4i_tcon_set_status+0x178/0x2f0)
[ 841.915269] [<c0694624>] (sun4i_tcon_set_status) from [<c06930c0>] (sun4i_crtc_atomic_disable+0x7c/0xe4)
[ 841.915279] [<c06930c0>] (sun4i_crtc_atomic_disable) from [<c06637fc>] (drm_atomic_helper_commit_modeset_disables+0x390/0x46c)
[ 841.915288] [<c06637fc>] (drm_atomic_helper_commit_modeset_disables) from [<c0664df4>] (drm_atomic_helper_commit_tail_rpm+0x18/0x64)
[ 841.915295] [<c0664df4>] (drm_atomic_helper_commit_tail_rpm) from [<c0664da8>] (commit_tail+0x40/0x6c)
[ 841.915302] [<c0664da8>] (commit_tail) from [<c06652b0>] (drm_atomic_helper_commit+0xbc/0x128)
[ 841.915311] [<c06652b0>] (drm_atomic_helper_commit) from [<c0668d40>] (restore_fbdev_mode_atomic+0x100/0x1fc)
[ 841.915319] [<c0668d40>] (restore_fbdev_mode_atomic) from [<c0668f1c>] (drm_fb_helper_dpms+0x50/0x130)
[ 841.915328] [<c0668f1c>] (drm_fb_helper_dpms) from [<c0669e9c>] (drm_fb_helper_blank+0x54/0x90)
[ 841.915337] [<c0669e9c>] (drm_fb_helper_blank) from [<c06088cc>] (fb_blank+0x54/0xa8)
[ 841.915343] [<c06088cc>] (fb_blank) from [<c0608c80>] (do_fb_ioctl+0x360/0x62c)
[ 841.915351] [<c0608c80>] (do_fb_ioctl) from [<c0362648>] (do_vfs_ioctl+0x9c/0x774)
[ 841.915358] [<c0362648>] (do_vfs_ioctl) from [<c0362d54>] (SyS_ioctl+0x34/0x58)
[ 841.915364] [<c0362d54>] (SyS_ioctl) from [<c0201120>] (ret_fast_syscall+0x0/0x4c)
[ 841.915368] Exception stack(0xe5fc5fa8 to 0xe5fc5ff0)
[ 841.915373] 5fa0: 00674f10 00675460 0000000b 00004611 00000001 00000000
[ 841.915379] 5fc0: 00674f10 00675460 00000001 00000036 00650474 00000000 006504a4 00675df8
[ 841.915382] 5fe0: b61a502c be8acb2c b6192c38 b6b152ec
[ 841.915386] ---[ end trace fa81b956197707f8 ]---

It looks like clk_rate_exclusive_put inside sun4i_tcon_channel_set_status is
called without first calling some function that would call
clk_set_rate_exclusive, leading to unbalanced get/put calls.

regards,
o.

> static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon,
> --
> 2.16.2
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
> For more options, visit https://groups.google.com/d/optout.

2018-03-08 23:23:33

by Jernej Skrabec

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH v3 06/16] drm/sun4i: Release exclusive clock lock when disabling TCON

Hi,

Dne četrtek, 08. marec 2018 ob 23:47:17 CET je Ondřej Jirman napisal(a):
> Hi,
>
> On Thu, Mar 01, 2018 at 10:34:32PM +0100, Jernej Skrabec wrote:
> > Currently exclusive TCON clock lock is never released, which, for
> > example, prevents changing resolution on HDMI.
> >
> > In order to fix that, release clock when disabling TCON. TCON is always
> > disabled first before new mode is set.
> >
> > Signed-off-by: Jernej Skrabec <[email protected]>
> > ---
> >
> > drivers/gpu/drm/sun4i/sun4i_tcon.c | 6 ++++--
> > 1 file changed, 4 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 1d714c06ec9d..7f6c4125c89f
> > 100644
> > --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > @@ -102,10 +102,12 @@ static void sun4i_tcon_channel_set_status(struct
> > sun4i_tcon *tcon, int channel,>
> > return;
> >
> > }
> >
> > - if (enabled)
> > + if (enabled) {
> >
> > clk_prepare_enable(clk);
> >
> > - else
> > + } else {
> > + clk_rate_exclusive_put(clk);
> >
> > clk_disable_unprepare(clk);
> >
> > + }
> >
> > }
>
> At least in the linux-next/master I can't see clk_rate_exclusive_get call:
>

It is in drm-misc/drm-misc-fixes:
https://cgit.freedesktop.org/drm/drm-misc/commit/?h=drm-misc-fixes&id=79d103a565d16b1893d990b2ee5e0fe71767759f

My patch is also applied in same branch, so there should be no issues while
merging all those branches.

linux-next doesn't have either patches currently: https://git.kernel.org/pub/
scm/linux/kernel/git/next/linux-next.git/log/drivers/gpu/drm/sun4i

This is issue only if you manually apply one patch without the other.

Best regards,
Jernej

> $ git grep 'exclusive' linux-next/master -- drivers/gpu/drm/sun4i
>
> linux-next/master:sun4i_hdmi.h: * On sun5i the threshold is exclusive,
> i.e. does not include, linux-next/master:sun4i_tcon.c:
> clk_rate_exclusive_put(clk); linux-next/master:sun4i_tcon.c:
> clk_set_rate_exclusive(tcon->dclk, mode->crtc_clock * 1000);
> linux-next/master:sun4i_tcon.c: clk_set_rate_exclusive(tcon->sclk1,
> mode->crtc_clock * 1000);
>
> and the kernel complains too:
>
> [ 841.915161] ------------[ cut here ]------------
> [ 841.915187] WARNING: CPU: 0 PID: 273 at
> /workspace/megous.com/orangepi-pc/linux-4.16/drivers/clk/clk.c:608
> clk_rate_exclusive_put+0x48/0x4c [ 841.915194] CPU: 0 PID: 273 Comm: Xorg
> Not tainted 4.16.0-rc4-00268-gbac2ecf73ed0 #13 [ 841.915196] Hardware
> name: Allwinner sun8i Family
> [ 841.915217] [<c0228440>] (unwind_backtrace) from [<c0225b90>]
> (show_stack+0x10/0x14) [ 841.915228] [<c0225b90>] (show_stack) from
> [<c0b094bc>] (dump_stack+0x88/0x9c) [ 841.915237] [<c0b094bc>]
> (dump_stack) from [<c0240294>] (__warn+0xd4/0xf0) [ 841.915244]
> [<c0240294>] (__warn) from [<c0240380>] (warn_slowpath_null+0x40/0x48) [
> 841.915250] [<c0240380>] (warn_slowpath_null) from [<c0619b6c>]
> (clk_rate_exclusive_put+0x48/0x4c) [ 841.915261] [<c0619b6c>]
> (clk_rate_exclusive_put) from [<c0694624>]
> (sun4i_tcon_set_status+0x178/0x2f0) [ 841.915269] [<c0694624>]
> (sun4i_tcon_set_status) from [<c06930c0>]
> (sun4i_crtc_atomic_disable+0x7c/0xe4) [ 841.915279] [<c06930c0>]
> (sun4i_crtc_atomic_disable) from [<c06637fc>]
> (drm_atomic_helper_commit_modeset_disables+0x390/0x46c) [ 841.915288]
> [<c06637fc>] (drm_atomic_helper_commit_modeset_disables) from [<c0664df4>]
> (drm_atomic_helper_commit_tail_rpm+0x18/0x64) [ 841.915295] [<c0664df4>]
> (drm_atomic_helper_commit_tail_rpm) from [<c0664da8>]
> (commit_tail+0x40/0x6c) [ 841.915302] [<c0664da8>] (commit_tail) from
> [<c06652b0>] (drm_atomic_helper_commit+0xbc/0x128) [ 841.915311]
> [<c06652b0>] (drm_atomic_helper_commit) from [<c0668d40>]
> (restore_fbdev_mode_atomic+0x100/0x1fc) [ 841.915319] [<c0668d40>]
> (restore_fbdev_mode_atomic) from [<c0668f1c>]
> (drm_fb_helper_dpms+0x50/0x130) [ 841.915328] [<c0668f1c>]
> (drm_fb_helper_dpms) from [<c0669e9c>] (drm_fb_helper_blank+0x54/0x90) [
> 841.915337] [<c0669e9c>] (drm_fb_helper_blank) from [<c06088cc>]
> (fb_blank+0x54/0xa8) [ 841.915343] [<c06088cc>] (fb_blank) from
> [<c0608c80>] (do_fb_ioctl+0x360/0x62c) [ 841.915351] [<c0608c80>]
> (do_fb_ioctl) from [<c0362648>] (do_vfs_ioctl+0x9c/0x774) [ 841.915358]
> [<c0362648>] (do_vfs_ioctl) from [<c0362d54>] (SyS_ioctl+0x34/0x58) [
> 841.915364] [<c0362d54>] (SyS_ioctl) from [<c0201120>]
> (ret_fast_syscall+0x0/0x4c) [ 841.915368] Exception stack(0xe5fc5fa8 to
> 0xe5fc5ff0)
> [ 841.915373] 5fa0: 00674f10 00675460 0000000b 00004611
> 00000001 00000000 [ 841.915379] 5fc0: 00674f10 00675460 00000001 00000036
> 00650474 00000000 006504a4 00675df8 [ 841.915382] 5fe0: b61a502c be8acb2c
> b6192c38 b6b152ec
> [ 841.915386] ---[ end trace fa81b956197707f8 ]---
>
> It looks like clk_rate_exclusive_put inside sun4i_tcon_channel_set_status is
> called without first calling some function that would call
> clk_set_rate_exclusive, leading to unbalanced get/put calls.
>
> regards,
> o.
>
> > static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon,
> >
> > --
> > 2.16.2
> >
> > --
> > You received this message because you are subscribed to the Google Groups
> > "linux-sunxi" group. To unsubscribe from this group and stop receiving
> > emails from it, send an email to
> > [email protected]. For more options, visit
> > https://groups.google.com/d/optout.





2018-03-09 00:14:50

by Ondřej Jirman

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH v3 06/16] drm/sun4i: Release exclusive clock lock when disabling TCON

Hi Jernej,

On Thu, Mar 08, 2018 at 11:57:40PM +0100, Jernej Škrabec wrote:
> Hi,
>
> Dne četrtek, 08. marec 2018 ob 23:47:17 CET je Ondřej Jirman napisal(a):
> > Hi,
> >
> > On Thu, Mar 01, 2018 at 10:34:32PM +0100, Jernej Skrabec wrote:
> > > Currently exclusive TCON clock lock is never released, which, for
> > > example, prevents changing resolution on HDMI.
> > >
> > > In order to fix that, release clock when disabling TCON. TCON is always
> > > disabled first before new mode is set.
> > >
> > > Signed-off-by: Jernej Skrabec <[email protected]>
> > > ---
> > >
> > > drivers/gpu/drm/sun4i/sun4i_tcon.c | 6 ++++--
> > > 1 file changed, 4 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > > b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 1d714c06ec9d..7f6c4125c89f
> > > 100644
> > > --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > > +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > > @@ -102,10 +102,12 @@ static void sun4i_tcon_channel_set_status(struct
> > > sun4i_tcon *tcon, int channel,>
> > > return;
> > >
> > > }
> > >
> > > - if (enabled)
> > > + if (enabled) {
> > >
> > > clk_prepare_enable(clk);
> > >
> > > - else
> > > + } else {
> > > + clk_rate_exclusive_put(clk);
> > >
> > > clk_disable_unprepare(clk);
> > >
> > > + }
> > >
> > > }
> >
> > At least in the linux-next/master I can't see clk_rate_exclusive_get call:
> >
>
> It is in drm-misc/drm-misc-fixes:
> https://cgit.freedesktop.org/drm/drm-misc/commit/?h=drm-misc-fixes&id=79d103a565d16b1893d990b2ee5e0fe71767759f
>
> My patch is also applied in same branch, so there should be no issues while
> merging all those branches.
>
> linux-next doesn't have either patches currently: https://git.kernel.org/pub/
> scm/linux/kernel/git/next/linux-next.git/log/drivers/gpu/drm/sun4i
>
> This is issue only if you manually apply one patch without the other.

I have (and had) both patches applied. There's perhaps some code path,
where sun4i_tcon_channel_set_status(..., false) is called in unbalanced
way with regards to clk_set_rate_exclusive().

The issue occurs when starting Xorg. But Xorg works fine.

regards,
o.

> Best regards,
> Jernej
>
> > $ git grep 'exclusive' linux-next/master -- drivers/gpu/drm/sun4i
> >
> > linux-next/master:sun4i_hdmi.h: * On sun5i the threshold is exclusive,
> > i.e. does not include, linux-next/master:sun4i_tcon.c:
> > clk_rate_exclusive_put(clk); linux-next/master:sun4i_tcon.c:
> > clk_set_rate_exclusive(tcon->dclk, mode->crtc_clock * 1000);
> > linux-next/master:sun4i_tcon.c: clk_set_rate_exclusive(tcon->sclk1,
> > mode->crtc_clock * 1000);
> >
> > and the kernel complains too:
> >
> > [ 841.915161] ------------[ cut here ]------------
> > [ 841.915187] WARNING: CPU: 0 PID: 273 at
> > /workspace/megous.com/orangepi-pc/linux-4.16/drivers/clk/clk.c:608
> > clk_rate_exclusive_put+0x48/0x4c [ 841.915194] CPU: 0 PID: 273 Comm: Xorg
> > Not tainted 4.16.0-rc4-00268-gbac2ecf73ed0 #13 [ 841.915196] Hardware
> > name: Allwinner sun8i Family
> > [ 841.915217] [<c0228440>] (unwind_backtrace) from [<c0225b90>]
> > (show_stack+0x10/0x14) [ 841.915228] [<c0225b90>] (show_stack) from
> > [<c0b094bc>] (dump_stack+0x88/0x9c) [ 841.915237] [<c0b094bc>]
> > (dump_stack) from [<c0240294>] (__warn+0xd4/0xf0) [ 841.915244]
> > [<c0240294>] (__warn) from [<c0240380>] (warn_slowpath_null+0x40/0x48) [
> > 841.915250] [<c0240380>] (warn_slowpath_null) from [<c0619b6c>]
> > (clk_rate_exclusive_put+0x48/0x4c) [ 841.915261] [<c0619b6c>]
> > (clk_rate_exclusive_put) from [<c0694624>]
> > (sun4i_tcon_set_status+0x178/0x2f0) [ 841.915269] [<c0694624>]
> > (sun4i_tcon_set_status) from [<c06930c0>]
> > (sun4i_crtc_atomic_disable+0x7c/0xe4) [ 841.915279] [<c06930c0>]
> > (sun4i_crtc_atomic_disable) from [<c06637fc>]
> > (drm_atomic_helper_commit_modeset_disables+0x390/0x46c) [ 841.915288]
> > [<c06637fc>] (drm_atomic_helper_commit_modeset_disables) from [<c0664df4>]
> > (drm_atomic_helper_commit_tail_rpm+0x18/0x64) [ 841.915295] [<c0664df4>]
> > (drm_atomic_helper_commit_tail_rpm) from [<c0664da8>]
> > (commit_tail+0x40/0x6c) [ 841.915302] [<c0664da8>] (commit_tail) from
> > [<c06652b0>] (drm_atomic_helper_commit+0xbc/0x128) [ 841.915311]
> > [<c06652b0>] (drm_atomic_helper_commit) from [<c0668d40>]
> > (restore_fbdev_mode_atomic+0x100/0x1fc) [ 841.915319] [<c0668d40>]
> > (restore_fbdev_mode_atomic) from [<c0668f1c>]
> > (drm_fb_helper_dpms+0x50/0x130) [ 841.915328] [<c0668f1c>]
> > (drm_fb_helper_dpms) from [<c0669e9c>] (drm_fb_helper_blank+0x54/0x90) [
> > 841.915337] [<c0669e9c>] (drm_fb_helper_blank) from [<c06088cc>]
> > (fb_blank+0x54/0xa8) [ 841.915343] [<c06088cc>] (fb_blank) from
> > [<c0608c80>] (do_fb_ioctl+0x360/0x62c) [ 841.915351] [<c0608c80>]
> > (do_fb_ioctl) from [<c0362648>] (do_vfs_ioctl+0x9c/0x774) [ 841.915358]
> > [<c0362648>] (do_vfs_ioctl) from [<c0362d54>] (SyS_ioctl+0x34/0x58) [
> > 841.915364] [<c0362d54>] (SyS_ioctl) from [<c0201120>]
> > (ret_fast_syscall+0x0/0x4c) [ 841.915368] Exception stack(0xe5fc5fa8 to
> > 0xe5fc5ff0)
> > [ 841.915373] 5fa0: 00674f10 00675460 0000000b 00004611
> > 00000001 00000000 [ 841.915379] 5fc0: 00674f10 00675460 00000001 00000036
> > 00650474 00000000 006504a4 00675df8 [ 841.915382] 5fe0: b61a502c be8acb2c
> > b6192c38 b6b152ec
> > [ 841.915386] ---[ end trace fa81b956197707f8 ]---
> >
> > It looks like clk_rate_exclusive_put inside sun4i_tcon_channel_set_status is
> > called without first calling some function that would call
> > clk_set_rate_exclusive, leading to unbalanced get/put calls.
> >
> > regards,
> > o.
> >
> > > static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon,
> > >
> > > --
> > > 2.16.2
> > >
> > > --
> > > You received this message because you are subscribed to the Google Groups
> > > "linux-sunxi" group. To unsubscribe from this group and stop receiving
> > > emails from it, send an email to
> > > [email protected]. For more options, visit
> > > https://groups.google.com/d/optout.
>
>
>
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
> For more options, visit https://groups.google.com/d/optout.

2018-03-09 00:46:38

by Ondřej Jirman

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH v3 06/16] drm/sun4i: Release exclusive clock lock when disabling TCON

Hi,

I've debugged this further and it seems that the code has incorrect assumptions.
See docs for mode_set_nofb.

https://elixir.bootlin.com/linux/v4.16-rc4/source/include/drm/drm_modeset_helper_vtables.h#L209

I've added traces to a few functions that call clk_.*exclusive.*() functions,
and I see this after a few restarts of Xorg server:

[ 0.783842] *** sun4i_tcon1_mode_set()
[ 0.783886] *** sun4i_tcon_channel_set_status(..., 1, true)
[ 6.881690] *** sun4i_tcon_channel_set_status(..., 1, false)
[ 6.881758] *** sun4i_tcon_channel_set_status(..., 1, true)
[ 52.335085] *** sun4i_tcon_channel_set_status(..., 1, false)
[ 52.335343] *** sun4i_tcon_channel_set_status(..., 1, true)
[ 68.921079] *** sun4i_tcon_channel_set_status(..., 1, false)
[ 68.921337] *** sun4i_tcon_channel_set_status(..., 1, true)

mode_set_nofb is called just once, yet sun4i_tcon_channel_set_status(..., 1, false)
is called multiple times, which leads to unbalanced calls to clk_set_rate_exclusive
and clk_rate_exclusive_put.

I don't know how to fix this.

regards,
o.

On Fri, Mar 09, 2018 at 01:13:14AM +0100, 'Ondřej Jirman' via linux-sunxi wrote:
> Hi Jernej,
>
> On Thu, Mar 08, 2018 at 11:57:40PM +0100, Jernej Škrabec wrote:
> > Hi,
> >
> > Dne četrtek, 08. marec 2018 ob 23:47:17 CET je Ondřej Jirman napisal(a):
> > > Hi,
> > >
> > > On Thu, Mar 01, 2018 at 10:34:32PM +0100, Jernej Skrabec wrote:
> > > > Currently exclusive TCON clock lock is never released, which, for
> > > > example, prevents changing resolution on HDMI.
> > > >
> > > > In order to fix that, release clock when disabling TCON. TCON is always
> > > > disabled first before new mode is set.
> > > >
> > > > Signed-off-by: Jernej Skrabec <[email protected]>
> > > > ---
> > > >
> > > > drivers/gpu/drm/sun4i/sun4i_tcon.c | 6 ++++--
> > > > 1 file changed, 4 insertions(+), 2 deletions(-)
> > > >
> > > > diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > > > b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 1d714c06ec9d..7f6c4125c89f
> > > > 100644
> > > > --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > > > +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > > > @@ -102,10 +102,12 @@ static void sun4i_tcon_channel_set_status(struct
> > > > sun4i_tcon *tcon, int channel,>
> > > > return;
> > > >
> > > > }
> > > >
> > > > - if (enabled)
> > > > + if (enabled) {
> > > >
> > > > clk_prepare_enable(clk);
> > > >
> > > > - else
> > > > + } else {
> > > > + clk_rate_exclusive_put(clk);
> > > >
> > > > clk_disable_unprepare(clk);
> > > >
> > > > + }
> > > >
> > > > }
> > >
> > > At least in the linux-next/master I can't see clk_rate_exclusive_get call:
> > >
> >
> > It is in drm-misc/drm-misc-fixes:
> > https://cgit.freedesktop.org/drm/drm-misc/commit/?h=drm-misc-fixes&id=79d103a565d16b1893d990b2ee5e0fe71767759f
> >
> > My patch is also applied in same branch, so there should be no issues while
> > merging all those branches.
> >
> > linux-next doesn't have either patches currently: https://git.kernel.org/pub/
> > scm/linux/kernel/git/next/linux-next.git/log/drivers/gpu/drm/sun4i
> >
> > This is issue only if you manually apply one patch without the other.
>
> I have (and had) both patches applied. There's perhaps some code path,
> where sun4i_tcon_channel_set_status(..., false) is called in unbalanced
> way with regards to clk_set_rate_exclusive().
>
> The issue occurs when starting Xorg. But Xorg works fine.
>
> regards,
> o.
>
> > Best regards,
> > Jernej
> >
> > > $ git grep 'exclusive' linux-next/master -- drivers/gpu/drm/sun4i
> > >
> > > linux-next/master:sun4i_hdmi.h: * On sun5i the threshold is exclusive,
> > > i.e. does not include, linux-next/master:sun4i_tcon.c:
> > > clk_rate_exclusive_put(clk); linux-next/master:sun4i_tcon.c:
> > > clk_set_rate_exclusive(tcon->dclk, mode->crtc_clock * 1000);
> > > linux-next/master:sun4i_tcon.c: clk_set_rate_exclusive(tcon->sclk1,
> > > mode->crtc_clock * 1000);
> > >
> > > and the kernel complains too:
> > >
> > > [ 841.915161] ------------[ cut here ]------------
> > > [ 841.915187] WARNING: CPU: 0 PID: 273 at
> > > /workspace/megous.com/orangepi-pc/linux-4.16/drivers/clk/clk.c:608
> > > clk_rate_exclusive_put+0x48/0x4c [ 841.915194] CPU: 0 PID: 273 Comm: Xorg
> > > Not tainted 4.16.0-rc4-00268-gbac2ecf73ed0 #13 [ 841.915196] Hardware
> > > name: Allwinner sun8i Family
> > > [ 841.915217] [<c0228440>] (unwind_backtrace) from [<c0225b90>]
> > > (show_stack+0x10/0x14) [ 841.915228] [<c0225b90>] (show_stack) from
> > > [<c0b094bc>] (dump_stack+0x88/0x9c) [ 841.915237] [<c0b094bc>]
> > > (dump_stack) from [<c0240294>] (__warn+0xd4/0xf0) [ 841.915244]
> > > [<c0240294>] (__warn) from [<c0240380>] (warn_slowpath_null+0x40/0x48) [
> > > 841.915250] [<c0240380>] (warn_slowpath_null) from [<c0619b6c>]
> > > (clk_rate_exclusive_put+0x48/0x4c) [ 841.915261] [<c0619b6c>]
> > > (clk_rate_exclusive_put) from [<c0694624>]
> > > (sun4i_tcon_set_status+0x178/0x2f0) [ 841.915269] [<c0694624>]
> > > (sun4i_tcon_set_status) from [<c06930c0>]
> > > (sun4i_crtc_atomic_disable+0x7c/0xe4) [ 841.915279] [<c06930c0>]
> > > (sun4i_crtc_atomic_disable) from [<c06637fc>]
> > > (drm_atomic_helper_commit_modeset_disables+0x390/0x46c) [ 841.915288]
> > > [<c06637fc>] (drm_atomic_helper_commit_modeset_disables) from [<c0664df4>]
> > > (drm_atomic_helper_commit_tail_rpm+0x18/0x64) [ 841.915295] [<c0664df4>]
> > > (drm_atomic_helper_commit_tail_rpm) from [<c0664da8>]
> > > (commit_tail+0x40/0x6c) [ 841.915302] [<c0664da8>] (commit_tail) from
> > > [<c06652b0>] (drm_atomic_helper_commit+0xbc/0x128) [ 841.915311]
> > > [<c06652b0>] (drm_atomic_helper_commit) from [<c0668d40>]
> > > (restore_fbdev_mode_atomic+0x100/0x1fc) [ 841.915319] [<c0668d40>]
> > > (restore_fbdev_mode_atomic) from [<c0668f1c>]
> > > (drm_fb_helper_dpms+0x50/0x130) [ 841.915328] [<c0668f1c>]
> > > (drm_fb_helper_dpms) from [<c0669e9c>] (drm_fb_helper_blank+0x54/0x90) [
> > > 841.915337] [<c0669e9c>] (drm_fb_helper_blank) from [<c06088cc>]
> > > (fb_blank+0x54/0xa8) [ 841.915343] [<c06088cc>] (fb_blank) from
> > > [<c0608c80>] (do_fb_ioctl+0x360/0x62c) [ 841.915351] [<c0608c80>]
> > > (do_fb_ioctl) from [<c0362648>] (do_vfs_ioctl+0x9c/0x774) [ 841.915358]
> > > [<c0362648>] (do_vfs_ioctl) from [<c0362d54>] (SyS_ioctl+0x34/0x58) [
> > > 841.915364] [<c0362d54>] (SyS_ioctl) from [<c0201120>]
> > > (ret_fast_syscall+0x0/0x4c) [ 841.915368] Exception stack(0xe5fc5fa8 to
> > > 0xe5fc5ff0)
> > > [ 841.915373] 5fa0: 00674f10 00675460 0000000b 00004611
> > > 00000001 00000000 [ 841.915379] 5fc0: 00674f10 00675460 00000001 00000036
> > > 00650474 00000000 006504a4 00675df8 [ 841.915382] 5fe0: b61a502c be8acb2c
> > > b6192c38 b6b152ec
> > > [ 841.915386] ---[ end trace fa81b956197707f8 ]---
> > >
> > > It looks like clk_rate_exclusive_put inside sun4i_tcon_channel_set_status is
> > > called without first calling some function that would call
> > > clk_set_rate_exclusive, leading to unbalanced get/put calls.
> > >
> > > regards,
> > > o.
> > >
> > > > static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon,
> > > >
> > > > --
> > > > 2.16.2
> > > >
> > > > --
> > > > You received this message because you are subscribed to the Google Groups
> > > > "linux-sunxi" group. To unsubscribe from this group and stop receiving
> > > > emails from it, send an email to
> > > > [email protected]. For more options, visit
> > > > https://groups.google.com/d/optout.
> >
> >
> >
> >
> > --
> > You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> > To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
> > For more options, visit https://groups.google.com/d/optout.
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
> For more options, visit https://groups.google.com/d/optout.

2018-03-09 06:20:53

by Jernej Skrabec

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH v3 06/16] drm/sun4i: Release exclusive clock lock when disabling TCON

Hi,

Dne petek, 09. marec 2018 ob 01:44:55 CET je Ondřej Jirman napisal(a):
> Hi,
>
> I've debugged this further and it seems that the code has incorrect
> assumptions. See docs for mode_set_nofb.
>
> https://elixir.bootlin.com/linux/v4.16-rc4/source/include/drm/drm_modeset_he
> lper_vtables.h#L209
>

Does this happen with https://github.com/jernejsk/linux-1/tree/h3_hdmi_v3 ?

I also tested running X, but I don't remember having the issue.

> I've added traces to a few functions that call clk_.*exclusive.*()
> functions, and I see this after a few restarts of Xorg server:
>
> [ 0.783842] *** sun4i_tcon1_mode_set()
> [ 0.783886] *** sun4i_tcon_channel_set_status(..., 1, true)
> [ 6.881690] *** sun4i_tcon_channel_set_status(..., 1, false)
> [ 6.881758] *** sun4i_tcon_channel_set_status(..., 1, true)
> [ 52.335085] *** sun4i_tcon_channel_set_status(..., 1, false)
> [ 52.335343] *** sun4i_tcon_channel_set_status(..., 1, true)
> [ 68.921079] *** sun4i_tcon_channel_set_status(..., 1, false)
> [ 68.921337] *** sun4i_tcon_channel_set_status(..., 1, true)
>
> mode_set_nofb is called just once, yet sun4i_tcon_channel_set_status(..., 1,
> false) is called multiple times, which leads to unbalanced calls to
> clk_set_rate_exclusive and clk_rate_exclusive_put.
>
> I don't know how to fix this.

Since there is no function to check if clock is protected, flag can be
introduced within TCON which is set when clock rate is protected and unset
when it is unprotected. That way we could track if clk_rate_exclusive_put()
needs to be called or not.

Best regards,
Jernej

>
> regards,
> o.
>
> On Fri, Mar 09, 2018 at 01:13:14AM +0100, 'Ondřej Jirman' via linux-sunxi
wrote:
> > Hi Jernej,
> >
> > On Thu, Mar 08, 2018 at 11:57:40PM +0100, Jernej Škrabec wrote:
> > > Hi,
> > >
> > > Dne četrtek, 08. marec 2018 ob 23:47:17 CET je Ondřej Jirman napisal(a):
> > > > Hi,
> > > >
> > > > On Thu, Mar 01, 2018 at 10:34:32PM +0100, Jernej Skrabec wrote:
> > > > > Currently exclusive TCON clock lock is never released, which, for
> > > > > example, prevents changing resolution on HDMI.
> > > > >
> > > > > In order to fix that, release clock when disabling TCON. TCON is
> > > > > always
> > > > > disabled first before new mode is set.
> > > > >
> > > > > Signed-off-by: Jernej Skrabec <[email protected]>
> > > > > ---
> > > > >
> > > > > drivers/gpu/drm/sun4i/sun4i_tcon.c | 6 ++++--
> > > > > 1 file changed, 4 insertions(+), 2 deletions(-)
> > > > >
> > > > > diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > > > > b/drivers/gpu/drm/sun4i/sun4i_tcon.c index
> > > > > 1d714c06ec9d..7f6c4125c89f
> > > > > 100644
> > > > > --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > > > > +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > > > > @@ -102,10 +102,12 @@ static void
> > > > > sun4i_tcon_channel_set_status(struct
> > > > > sun4i_tcon *tcon, int channel,>
> > > > >
> > > > > return;
> > > > >
> > > > > }
> > > > >
> > > > > - if (enabled)
> > > > > + if (enabled) {
> > > > >
> > > > > clk_prepare_enable(clk);
> > > > >
> > > > > - else
> > > > > + } else {
> > > > > + clk_rate_exclusive_put(clk);
> > > > >
> > > > > clk_disable_unprepare(clk);
> > > > >
> > > > > + }
> > > > >
> > > > > }
> > > >
> > > > At least in the linux-next/master I can't see clk_rate_exclusive_get
call:
> > > It is in drm-misc/drm-misc-fixes:
> > > https://cgit.freedesktop.org/drm/drm-misc/commit/?h=drm-misc-fixes&id=79
> > > d103a565d16b1893d990b2ee5e0fe71767759f
> > >
> > > My patch is also applied in same branch, so there should be no issues
> > > while
> > > merging all those branches.
> > >
> > > linux-next doesn't have either patches currently:
> > > https://git.kernel.org/pub/
> > > scm/linux/kernel/git/next/linux-next.git/log/drivers/gpu/drm/sun4i
> > >
> > > This is issue only if you manually apply one patch without the other.
> >
> > I have (and had) both patches applied. There's perhaps some code path,
> > where sun4i_tcon_channel_set_status(..., false) is called in unbalanced
> > way with regards to clk_set_rate_exclusive().
> >
> > The issue occurs when starting Xorg. But Xorg works fine.
> >
> > regards,
> >
> > o.
> >
> > > Best regards,
> > > Jernej
> > >
> > > > $ git grep 'exclusive' linux-next/master -- drivers/gpu/drm/sun4i
> > > >
> > > > linux-next/master:sun4i_hdmi.h: * On sun5i the threshold is
> > > > exclusive,
> > > > i.e. does not include, linux-next/master:sun4i_tcon.c:
> > > > clk_rate_exclusive_put(clk); linux-next/master:sun4i_tcon.c:
> > > > clk_set_rate_exclusive(tcon->dclk, mode->crtc_clock * 1000);
> > > > linux-next/master:sun4i_tcon.c: clk_set_rate_exclusive(tcon->sclk1,
> > > > mode->crtc_clock * 1000);
> > > >
> > > > and the kernel complains too:
> > > >
> > > > [ 841.915161] ------------[ cut here ]------------
> > > > [ 841.915187] WARNING: CPU: 0 PID: 273 at
> > > > /workspace/megous.com/orangepi-pc/linux-4.16/drivers/clk/clk.c:608
> > > > clk_rate_exclusive_put+0x48/0x4c [ 841.915194] CPU: 0 PID: 273 Comm:
> > > > Xorg
> > > > Not tainted 4.16.0-rc4-00268-gbac2ecf73ed0 #13 [ 841.915196] Hardware
> > > > name: Allwinner sun8i Family
> > > > [ 841.915217] [<c0228440>] (unwind_backtrace) from [<c0225b90>]
> > > > (show_stack+0x10/0x14) [ 841.915228] [<c0225b90>] (show_stack) from
> > > > [<c0b094bc>] (dump_stack+0x88/0x9c) [ 841.915237] [<c0b094bc>]
> > > > (dump_stack) from [<c0240294>] (__warn+0xd4/0xf0) [ 841.915244]
> > > > [<c0240294>] (__warn) from [<c0240380>] (warn_slowpath_null+0x40/0x48)
> > > > [
> > > > 841.915250] [<c0240380>] (warn_slowpath_null) from [<c0619b6c>]
> > > > (clk_rate_exclusive_put+0x48/0x4c) [ 841.915261] [<c0619b6c>]
> > > > (clk_rate_exclusive_put) from [<c0694624>]
> > > > (sun4i_tcon_set_status+0x178/0x2f0) [ 841.915269] [<c0694624>]
> > > > (sun4i_tcon_set_status) from [<c06930c0>]
> > > > (sun4i_crtc_atomic_disable+0x7c/0xe4) [ 841.915279] [<c06930c0>]
> > > > (sun4i_crtc_atomic_disable) from [<c06637fc>]
> > > > (drm_atomic_helper_commit_modeset_disables+0x390/0x46c) [ 841.915288]
> > > > [<c06637fc>] (drm_atomic_helper_commit_modeset_disables) from
> > > > [<c0664df4>]
> > > > (drm_atomic_helper_commit_tail_rpm+0x18/0x64) [ 841.915295]
> > > > [<c0664df4>]
> > > > (drm_atomic_helper_commit_tail_rpm) from [<c0664da8>]
> > > > (commit_tail+0x40/0x6c) [ 841.915302] [<c0664da8>] (commit_tail) from
> > > > [<c06652b0>] (drm_atomic_helper_commit+0xbc/0x128) [ 841.915311]
> > > > [<c06652b0>] (drm_atomic_helper_commit) from [<c0668d40>]
> > > > (restore_fbdev_mode_atomic+0x100/0x1fc) [ 841.915319] [<c0668d40>]
> > > > (restore_fbdev_mode_atomic) from [<c0668f1c>]
> > > > (drm_fb_helper_dpms+0x50/0x130) [ 841.915328] [<c0668f1c>]
> > > > (drm_fb_helper_dpms) from [<c0669e9c>] (drm_fb_helper_blank+0x54/0x90)
> > > > [
> > > > 841.915337] [<c0669e9c>] (drm_fb_helper_blank) from [<c06088cc>]
> > > > (fb_blank+0x54/0xa8) [ 841.915343] [<c06088cc>] (fb_blank) from
> > > > [<c0608c80>] (do_fb_ioctl+0x360/0x62c) [ 841.915351] [<c0608c80>]
> > > > (do_fb_ioctl) from [<c0362648>] (do_vfs_ioctl+0x9c/0x774) [
> > > > 841.915358]
> > > > [<c0362648>] (do_vfs_ioctl) from [<c0362d54>] (SyS_ioctl+0x34/0x58) [
> > > > 841.915364] [<c0362d54>] (SyS_ioctl) from [<c0201120>]
> > > > (ret_fast_syscall+0x0/0x4c) [ 841.915368] Exception stack(0xe5fc5fa8
> > > > to
> > > > 0xe5fc5ff0)
> > > > [ 841.915373] 5fa0: 00674f10 00675460 0000000b
> > > > 00004611
> > > > 00000001 00000000 [ 841.915379] 5fc0: 00674f10 00675460 00000001
> > > > 00000036
> > > > 00650474 00000000 006504a4 00675df8 [ 841.915382] 5fe0: b61a502c
> > > > be8acb2c
> > > > b6192c38 b6b152ec
> > > > [ 841.915386] ---[ end trace fa81b956197707f8 ]---
> > > >
> > > > It looks like clk_rate_exclusive_put inside
> > > > sun4i_tcon_channel_set_status is called without first calling some
> > > > function that would call
> > > > clk_set_rate_exclusive, leading to unbalanced get/put calls.
> > > >
> > > > regards,
> > > >
> > > > o.
> > > >
> > > > > static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon,
> > > > >
> > > > > --
> > > > > 2.16.2
> > > > >
> > > > > --
> > > > > You received this message because you are subscribed to the Google
> > > > > Groups
> > > > > "linux-sunxi" group. To unsubscribe from this group and stop
> > > > > receiving
> > > > > emails from it, send an email to
> > > > > [email protected]. For more options, visit
> > > > > https://groups.google.com/d/optout.
> > >
> > > --
> > > You received this message because you are subscribed to the Google
> > > Groups "linux-sunxi" group. To unsubscribe from this group and stop
> > > receiving emails from it, send an email to
> > > [email protected]. For more options, visit
> > > https://groups.google.com/d/optout.
> >
> > --
> > You received this message because you are subscribed to the Google Groups
> > "linux-sunxi" group. To unsubscribe from this group and stop receiving
> > emails from it, send an email to
> > [email protected]. For more options, visit
> > https://groups.google.com/d/optout.





2018-03-09 07:57:15

by Ondřej Jirman

[permalink] [raw]
Subject: Re: [linux-sunxi] [PATCH v3 06/16] drm/sun4i: Release exclusive clock lock when disabling TCON

Hi,

On Fri, Mar 09, 2018 at 07:19:33AM +0100, Jernej Škrabec wrote:
> Hi,
>
> Dne petek, 09. marec 2018 ob 01:44:55 CET je Ondřej Jirman napisal(a):
> > Hi,
> >
> > I've debugged this further and it seems that the code has incorrect
> > assumptions. See docs for mode_set_nofb.
> >
> > https://elixir.bootlin.com/linux/v4.16-rc4/source/include/drm/drm_modeset_he
> > lper_vtables.h#L209
> >
>
> Does this happen with https://github.com/jernejsk/linux-1/tree/h3_hdmi_v3 ?

Haven't tested, but it probably does, looking at the code. Try
restarting the X server a bunch of times.

> I also tested running X, but I don't remember having the issue.
>
> > I've added traces to a few functions that call clk_.*exclusive.*()
> > functions, and I see this after a few restarts of Xorg server:
> >
> > [ 0.783842] *** sun4i_tcon1_mode_set()
> > [ 0.783886] *** sun4i_tcon_channel_set_status(..., 1, true)
> > [ 6.881690] *** sun4i_tcon_channel_set_status(..., 1, false)
> > [ 6.881758] *** sun4i_tcon_channel_set_status(..., 1, true)
> > [ 52.335085] *** sun4i_tcon_channel_set_status(..., 1, false)
> > [ 52.335343] *** sun4i_tcon_channel_set_status(..., 1, true)
> > [ 68.921079] *** sun4i_tcon_channel_set_status(..., 1, false)
> > [ 68.921337] *** sun4i_tcon_channel_set_status(..., 1, true)
> >
> > mode_set_nofb is called just once, yet sun4i_tcon_channel_set_status(..., 1,
> > false) is called multiple times, which leads to unbalanced calls to
> > clk_set_rate_exclusive and clk_rate_exclusive_put.
> >
> > I don't know how to fix this.
>
> Since there is no function to check if clock is protected, flag can be
> introduced within TCON which is set when clock rate is protected and unset
> when it is unprotected. That way we could track if clk_rate_exclusive_put()
> needs to be called or not.

I think that will not help. Protection is set in sun4i_tcon1_mode_set()
and that's called only once, but sun4i_tcon_channel_set_status(..., 1, false)
can be called multiple times, so the first call would disable protection
and the clock would be unprotected from then on, even though the display
would be active.

Perhaps the protection needs to be enabled in sun4i_tcon_channel_set_status(...,
true).

regards,
o.

> Best regards,
> Jernej
>
> >
> > regards,
> > o.
> >
> > On Fri, Mar 09, 2018 at 01:13:14AM +0100, 'Ondřej Jirman' via linux-sunxi
> wrote:
> > > Hi Jernej,
> > >
> > > On Thu, Mar 08, 2018 at 11:57:40PM +0100, Jernej Škrabec wrote:
> > > > Hi,
> > > >
> > > > Dne četrtek, 08. marec 2018 ob 23:47:17 CET je Ondřej Jirman napisal(a):
> > > > > Hi,
> > > > >
> > > > > On Thu, Mar 01, 2018 at 10:34:32PM +0100, Jernej Skrabec wrote:
> > > > > > Currently exclusive TCON clock lock is never released, which, for
> > > > > > example, prevents changing resolution on HDMI.
> > > > > >
> > > > > > In order to fix that, release clock when disabling TCON. TCON is
> > > > > > always
> > > > > > disabled first before new mode is set.
> > > > > >
> > > > > > Signed-off-by: Jernej Skrabec <[email protected]>
> > > > > > ---
> > > > > >
> > > > > > drivers/gpu/drm/sun4i/sun4i_tcon.c | 6 ++++--
> > > > > > 1 file changed, 4 insertions(+), 2 deletions(-)
> > > > > >
> > > > > > diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > > > > > b/drivers/gpu/drm/sun4i/sun4i_tcon.c index
> > > > > > 1d714c06ec9d..7f6c4125c89f
> > > > > > 100644
> > > > > > --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > > > > > +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > > > > > @@ -102,10 +102,12 @@ static void
> > > > > > sun4i_tcon_channel_set_status(struct
> > > > > > sun4i_tcon *tcon, int channel,>
> > > > > >
> > > > > > return;
> > > > > >
> > > > > > }
> > > > > >
> > > > > > - if (enabled)
> > > > > > + if (enabled) {
> > > > > >
> > > > > > clk_prepare_enable(clk);
> > > > > >
> > > > > > - else
> > > > > > + } else {
> > > > > > + clk_rate_exclusive_put(clk);
> > > > > >
> > > > > > clk_disable_unprepare(clk);
> > > > > >
> > > > > > + }
> > > > > >
> > > > > > }
> > > > >
> > > > > At least in the linux-next/master I can't see clk_rate_exclusive_get
> call:
> > > > It is in drm-misc/drm-misc-fixes:
> > > > https://cgit.freedesktop.org/drm/drm-misc/commit/?h=drm-misc-fixes&id=79
> > > > d103a565d16b1893d990b2ee5e0fe71767759f
> > > >
> > > > My patch is also applied in same branch, so there should be no issues
> > > > while
> > > > merging all those branches.
> > > >
> > > > linux-next doesn't have either patches currently:
> > > > https://git.kernel.org/pub/
> > > > scm/linux/kernel/git/next/linux-next.git/log/drivers/gpu/drm/sun4i
> > > >
> > > > This is issue only if you manually apply one patch without the other.
> > >
> > > I have (and had) both patches applied. There's perhaps some code path,
> > > where sun4i_tcon_channel_set_status(..., false) is called in unbalanced
> > > way with regards to clk_set_rate_exclusive().
> > >
> > > The issue occurs when starting Xorg. But Xorg works fine.
> > >
> > > regards,
> > >
> > > o.
> > >
> > > > Best regards,
> > > > Jernej
> > > >
> > > > > $ git grep 'exclusive' linux-next/master -- drivers/gpu/drm/sun4i
> > > > >
> > > > > linux-next/master:sun4i_hdmi.h: * On sun5i the threshold is
> > > > > exclusive,
> > > > > i.e. does not include, linux-next/master:sun4i_tcon.c:
> > > > > clk_rate_exclusive_put(clk); linux-next/master:sun4i_tcon.c:
> > > > > clk_set_rate_exclusive(tcon->dclk, mode->crtc_clock * 1000);
> > > > > linux-next/master:sun4i_tcon.c: clk_set_rate_exclusive(tcon->sclk1,
> > > > > mode->crtc_clock * 1000);
> > > > >
> > > > > and the kernel complains too:
> > > > >
> > > > > [ 841.915161] ------------[ cut here ]------------
> > > > > [ 841.915187] WARNING: CPU: 0 PID: 273 at
> > > > > /workspace/megous.com/orangepi-pc/linux-4.16/drivers/clk/clk.c:608
> > > > > clk_rate_exclusive_put+0x48/0x4c [ 841.915194] CPU: 0 PID: 273 Comm:
> > > > > Xorg
> > > > > Not tainted 4.16.0-rc4-00268-gbac2ecf73ed0 #13 [ 841.915196] Hardware
> > > > > name: Allwinner sun8i Family
> > > > > [ 841.915217] [<c0228440>] (unwind_backtrace) from [<c0225b90>]
> > > > > (show_stack+0x10/0x14) [ 841.915228] [<c0225b90>] (show_stack) from
> > > > > [<c0b094bc>] (dump_stack+0x88/0x9c) [ 841.915237] [<c0b094bc>]
> > > > > (dump_stack) from [<c0240294>] (__warn+0xd4/0xf0) [ 841.915244]
> > > > > [<c0240294>] (__warn) from [<c0240380>] (warn_slowpath_null+0x40/0x48)
> > > > > [
> > > > > 841.915250] [<c0240380>] (warn_slowpath_null) from [<c0619b6c>]
> > > > > (clk_rate_exclusive_put+0x48/0x4c) [ 841.915261] [<c0619b6c>]
> > > > > (clk_rate_exclusive_put) from [<c0694624>]
> > > > > (sun4i_tcon_set_status+0x178/0x2f0) [ 841.915269] [<c0694624>]
> > > > > (sun4i_tcon_set_status) from [<c06930c0>]
> > > > > (sun4i_crtc_atomic_disable+0x7c/0xe4) [ 841.915279] [<c06930c0>]
> > > > > (sun4i_crtc_atomic_disable) from [<c06637fc>]
> > > > > (drm_atomic_helper_commit_modeset_disables+0x390/0x46c) [ 841.915288]
> > > > > [<c06637fc>] (drm_atomic_helper_commit_modeset_disables) from
> > > > > [<c0664df4>]
> > > > > (drm_atomic_helper_commit_tail_rpm+0x18/0x64) [ 841.915295]
> > > > > [<c0664df4>]
> > > > > (drm_atomic_helper_commit_tail_rpm) from [<c0664da8>]
> > > > > (commit_tail+0x40/0x6c) [ 841.915302] [<c0664da8>] (commit_tail) from
> > > > > [<c06652b0>] (drm_atomic_helper_commit+0xbc/0x128) [ 841.915311]
> > > > > [<c06652b0>] (drm_atomic_helper_commit) from [<c0668d40>]
> > > > > (restore_fbdev_mode_atomic+0x100/0x1fc) [ 841.915319] [<c0668d40>]
> > > > > (restore_fbdev_mode_atomic) from [<c0668f1c>]
> > > > > (drm_fb_helper_dpms+0x50/0x130) [ 841.915328] [<c0668f1c>]
> > > > > (drm_fb_helper_dpms) from [<c0669e9c>] (drm_fb_helper_blank+0x54/0x90)
> > > > > [
> > > > > 841.915337] [<c0669e9c>] (drm_fb_helper_blank) from [<c06088cc>]
> > > > > (fb_blank+0x54/0xa8) [ 841.915343] [<c06088cc>] (fb_blank) from
> > > > > [<c0608c80>] (do_fb_ioctl+0x360/0x62c) [ 841.915351] [<c0608c80>]
> > > > > (do_fb_ioctl) from [<c0362648>] (do_vfs_ioctl+0x9c/0x774) [
> > > > > 841.915358]
> > > > > [<c0362648>] (do_vfs_ioctl) from [<c0362d54>] (SyS_ioctl+0x34/0x58) [
> > > > > 841.915364] [<c0362d54>] (SyS_ioctl) from [<c0201120>]
> > > > > (ret_fast_syscall+0x0/0x4c) [ 841.915368] Exception stack(0xe5fc5fa8
> > > > > to
> > > > > 0xe5fc5ff0)
> > > > > [ 841.915373] 5fa0: 00674f10 00675460 0000000b
> > > > > 00004611
> > > > > 00000001 00000000 [ 841.915379] 5fc0: 00674f10 00675460 00000001
> > > > > 00000036
> > > > > 00650474 00000000 006504a4 00675df8 [ 841.915382] 5fe0: b61a502c
> > > > > be8acb2c
> > > > > b6192c38 b6b152ec
> > > > > [ 841.915386] ---[ end trace fa81b956197707f8 ]---
> > > > >
> > > > > It looks like clk_rate_exclusive_put inside
> > > > > sun4i_tcon_channel_set_status is called without first calling some
> > > > > function that would call
> > > > > clk_set_rate_exclusive, leading to unbalanced get/put calls.
> > > > >
> > > > > regards,
> > > > >
> > > > > o.
> > > > >
> > > > > > static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon,
> > > > > >
> > > > > > --
> > > > > > 2.16.2
> > > > > >
> > > > > > --
> > > > > > You received this message because you are subscribed to the Google
> > > > > > Groups
> > > > > > "linux-sunxi" group. To unsubscribe from this group and stop
> > > > > > receiving
> > > > > > emails from it, send an email to
> > > > > > [email protected]. For more options, visit
> > > > > > https://groups.google.com/d/optout.
> > > >
> > > > --
> > > > You received this message because you are subscribed to the Google
> > > > Groups "linux-sunxi" group. To unsubscribe from this group and stop
> > > > receiving emails from it, send an email to
> > > > [email protected]. For more options, visit
> > > > https://groups.google.com/d/optout.
> > >
> > > --
> > > You received this message because you are subscribed to the Google Groups
> > > "linux-sunxi" group. To unsubscribe from this group and stop receiving
> > > emails from it, send an email to
> > > [email protected]. For more options, visit
> > > https://groups.google.com/d/optout.
>
>
>
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
> For more options, visit https://groups.google.com/d/optout.