All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/19] video: sunxi: rework DE2 driver
@ 2021-03-06 19:54 Jernej Skrabec
  2021-03-06 19:54 ` [PATCH v2 01/19] sunxi: video: select dw-hdmi in Kconfig, not Makefile Jernej Skrabec
                   ` (18 more replies)
  0 siblings, 19 replies; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

This series greatly reworks DE2 mixer and accompanying DW-HDMI platform
driver. Main goal was to use as many information from device tree as
possible and thus removing SoC speficic ifdefs from the code. This was
largely accomplished for mixer, HDMI and HDMI PHY driver.

Most of these changes are not user visible. Only improvements relevant
to the user are filtering HDMI modes based on pixel clock and searching
for additional detailed timings in EDID extension block. This change
allows me to use 4k monitor that I have - base EDID block on this monitor
holds only 4k at 60 detailed timing. Other detailed timings, which are
appropriate for HDMI 1.4 controller, are contained in extension block.

There is plenty of work to do. TCON handling should go to dedicated
driver and clock related code in TCON and DW-HDMI code should be moved
to clock drivers.

Testing was done only on H3.

Best regards,
Jernej

Changes from v1:
- collected tags
- reword some commit messages
- dropped patch 13 and 14 from v1
- 2 new patches, first add HDMI PHY driver and another drops PHY
  code from sunxi dw-hdmi driver and uses separate driver instead

Jernej Skrabec (19):
  sunxi: video: select dw-hdmi in Kconfig, not Makefile
  video: sunxi: Add mode_valid callback to sunxi_dw_hdmi
  common: edid: check for digital display earlier
  common: edid: extract code for detailed timing search
  common: edid: Search for valid timing in extension block
  video: sunxi: Use DW-HDMI hpd function
  video: sunxi: Remove check for ddc-i2c-bus property
  video: sunxi: Remove TV probe from DE2
  video: sunxi: de2: switch to public uclass functions
  video: sunxi: dw-hdmi: probe driver by compatible
  video: sunxi: dw-hdmi: read address from DT node
  video: sunxi: de2: switch to DT probing
  video: sunxi: de2: read address from DT node
  clk: sunxi: Add DE2 and HDMI clocks to H3 and A64
  clk: sunxi: add DE2 clock driver
  video: sunxi: de2: switch clock setup to DM model
  video: dw-hdmi: modify phy init callback to include full timings
  video: sunxi: Add DW HDMI PHY driver
  video: sunxi: dw-hdmi: Use new PHY driver

 arch/arm/mach-sunxi/Kconfig             |   3 +
 common/edid.c                           |  82 +++--
 drivers/clk/sunxi/Kconfig               |   5 +
 drivers/clk/sunxi/Makefile              |   1 +
 drivers/clk/sunxi/clk_a64.c             |  12 +
 drivers/clk/sunxi/clk_de2.c             |  85 +++++
 drivers/clk/sunxi/clk_h3.c              |  12 +
 drivers/video/dw_hdmi.c                 |   6 +-
 drivers/video/meson/meson_dw_hdmi.c     |   5 +-
 drivers/video/sunxi/Makefile            |   2 +-
 drivers/video/sunxi/sunxi_de2.c         | 191 +++++------
 drivers/video/sunxi/sunxi_dw_hdmi.c     | 300 ++++-------------
 drivers/video/sunxi/sunxi_dw_hdmi_phy.c | 423 ++++++++++++++++++++++++
 drivers/video/sunxi/sunxi_dw_hdmi_phy.h |  24 ++
 include/dw_hdmi.h                       |   4 +-
 15 files changed, 780 insertions(+), 375 deletions(-)
 create mode 100644 drivers/clk/sunxi/clk_de2.c
 create mode 100644 drivers/video/sunxi/sunxi_dw_hdmi_phy.c
 create mode 100644 drivers/video/sunxi/sunxi_dw_hdmi_phy.h

-- 
2.30.1

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 01/19] sunxi: video: select dw-hdmi in Kconfig, not Makefile
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-03-06 19:54 ` [PATCH v2 02/19] video: sunxi: Add mode_valid callback to sunxi_dw_hdmi Jernej Skrabec
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

Currently sunxi Makefile manually specifies full path to dw-hdmi common
code. However, that is not needed because it can be selected in Kconfig
instead.

Select proper symbol in Kconfig and drop path from Makefile.

Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 arch/arm/mach-sunxi/Kconfig  | 1 +
 drivers/video/sunxi/Makefile | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 0135575ca1eb..9149196b223e 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -972,6 +972,7 @@ config VIDEO_DE2
 	depends on SUNXI_DE2
 	select DM_VIDEO
 	select DISPLAY
+	select VIDEO_DW_HDMI
 	imply VIDEO_DT_SIMPLEFB
 	default y
 	---help---
diff --git a/drivers/video/sunxi/Makefile b/drivers/video/sunxi/Makefile
index 147e18799229..4321673312bf 100644
--- a/drivers/video/sunxi/Makefile
+++ b/drivers/video/sunxi/Makefile
@@ -4,4 +4,4 @@
 # Wolfgang Denk, DENX Software Engineering, wd at denx.de.
 
 obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o simplefb_common.o lcdc.o tve_common.o ../videomodes.o
-obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o simplefb_common.o lcdc.o ../dw_hdmi.o sunxi_lcd.o
+obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o simplefb_common.o lcdc.o sunxi_lcd.o
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 02/19] video: sunxi: Add mode_valid callback to sunxi_dw_hdmi
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
  2021-03-06 19:54 ` [PATCH v2 01/19] sunxi: video: select dw-hdmi in Kconfig, not Makefile Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-03-06 19:54 ` [PATCH v2 03/19] common: edid: check for digital display earlier Jernej Skrabec
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

Currently driver accepts all resolution which won't work on 4k screens.
Add validation callback which limits acceptable resolutions to 297 MHz.

Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 drivers/video/sunxi/sunxi_dw_hdmi.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c
index 0b8cefc311ef..e3811a2ec15f 100644
--- a/drivers/video/sunxi/sunxi_dw_hdmi.c
+++ b/drivers/video/sunxi/sunxi_dw_hdmi.c
@@ -305,6 +305,12 @@ static int sunxi_dw_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size)
 	return dw_hdmi_read_edid(&priv->hdmi, buf, buf_size);
 }
 
+static bool sunxi_dw_hdmi_mode_valid(struct udevice *dev,
+				     const struct display_timing *timing)
+{
+	return timing->pixelclock.typ <= 297000000;
+}
+
 static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp,
 				const struct display_timing *edid)
 {
@@ -388,6 +394,7 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev)
 static const struct dm_display_ops sunxi_dw_hdmi_ops = {
 	.read_edid = sunxi_dw_hdmi_read_edid,
 	.enable = sunxi_dw_hdmi_enable,
+	.mode_valid = sunxi_dw_hdmi_mode_valid,
 };
 
 U_BOOT_DRIVER(sunxi_dw_hdmi) = {
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 03/19] common: edid: check for digital display earlier
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
  2021-03-06 19:54 ` [PATCH v2 01/19] sunxi: video: select dw-hdmi in Kconfig, not Makefile Jernej Skrabec
  2021-03-06 19:54 ` [PATCH v2 02/19] video: sunxi: Add mode_valid callback to sunxi_dw_hdmi Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-03-06 19:54 ` [PATCH v2 04/19] common: edid: extract code for detailed timing search Jernej Skrabec
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

When searching for detailed timing in EDID, check for digital display
earlier. There is no point parsing other parameters if this flag is not
present.

Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 common/edid.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/common/edid.c b/common/edid.c
index 553ab8fd01a1..1cb7177742e8 100644
--- a/common/edid.c
+++ b/common/edid.c
@@ -185,6 +185,11 @@ int edid_get_timing_validate(u8 *buf, int buf_size,
 		return -EINVAL;
 	}
 
+	if (!EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid)) {
+		debug("%s: Not a digital display\n", __func__);
+		return -ENOSYS;
+	}
+
 	if (!EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(*edid)) {
 		debug("%s: No preferred timing\n", __func__);
 		return -ENOENT;
@@ -211,10 +216,6 @@ int edid_get_timing_validate(u8 *buf, int buf_size,
 	if (!timing_done)
 		return -EINVAL;
 
-	if (!EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid)) {
-		debug("%s: Not a digital display\n", __func__);
-		return -ENOSYS;
-	}
 	if (edid->version != 1 || edid->revision < 4) {
 		debug("%s: EDID version %d.%d does not have required info\n",
 		      __func__, edid->version, edid->revision);
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 04/19] common: edid: extract code for detailed timing search
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
                   ` (2 preceding siblings ...)
  2021-03-06 19:54 ` [PATCH v2 03/19] common: edid: check for digital display earlier Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-03-07  1:29   ` Andre Przywara
  2021-03-06 19:54 ` [PATCH v2 05/19] common: edid: Search for valid timing in extension block Jernej Skrabec
                   ` (14 subsequent siblings)
  18 siblings, 1 reply; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

Code which searches for valid detailed timing entry will be used in more
places. Extract it.

No functional change is made. However, descriptors are casted to
edid_detailed_timing instead of edid_monitor_descriptor. Descriptor can
be of either type, but since we're interested only in DTD, it is more
fitting to cast to edid_detailed_timing.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 common/edid.c | 49 ++++++++++++++++++++++++++++---------------------
 1 file changed, 28 insertions(+), 21 deletions(-)

diff --git a/common/edid.c b/common/edid.c
index 1cb7177742e8..a6c875d9c8e8 100644
--- a/common/edid.c
+++ b/common/edid.c
@@ -169,6 +169,29 @@ static bool cea_is_hdmi_vsdb_present(struct edid_cea861_info *info)
 	return false;
 }
 
+static bool edid_find_valid_timing(void *buf, int count,
+				   struct display_timing *timing,
+				   bool (*mode_valid)(void *priv,
+					const struct display_timing *timing),
+				   void *mode_valid_priv)
+{
+	struct edid_detailed_timing *t = buf;
+	bool found = false;
+	int i;
+
+	for (i = 0; i < count && !found; i++, t++)
+		if (EDID_DETAILED_TIMING_PIXEL_CLOCK(*t) != 0) {
+			decode_timing((u8 *)t, timing);
+			if (mode_valid)
+				found = mode_valid(mode_valid_priv,
+						   timing);
+			else
+				found = true;
+		}
+
+	return found;
+}
+
 int edid_get_timing_validate(u8 *buf, int buf_size,
 			     struct display_timing *timing,
 			     int *panel_bits_per_colourp,
@@ -177,8 +200,7 @@ int edid_get_timing_validate(u8 *buf, int buf_size,
 			     void *mode_valid_priv)
 {
 	struct edid1_info *edid = (struct edid1_info *)buf;
-	bool timing_done;
-	int i;
+	bool found;
 
 	if (buf_size < sizeof(*edid) || edid_check_info(edid)) {
 		debug("%s: Invalid buffer\n", __func__);
@@ -195,25 +217,10 @@ int edid_get_timing_validate(u8 *buf, int buf_size,
 		return -ENOENT;
 	}
 
-	/* Look for detailed timing */
-	timing_done = false;
-	for (i = 0; i < 4; i++) {
-		struct edid_monitor_descriptor *desc;
-
-		desc = &edid->monitor_details.descriptor[i];
-		if (desc->zero_flag_1 != 0) {
-			decode_timing((u8 *)desc, timing);
-			if (mode_valid)
-				timing_done = mode_valid(mode_valid_priv,
-							 timing);
-			else
-				timing_done = true;
-
-			if (timing_done)
-				break;
-		}
-	}
-	if (!timing_done)
+	/* Look for detailed timing in base EDID */
+	found = edid_find_valid_timing(edid->monitor_details.descriptor, 4,
+				       timing, mode_valid, mode_valid_priv);
+	if (!found)
 		return -EINVAL;
 
 	if (edid->version != 1 || edid->revision < 4) {
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 05/19] common: edid: Search for valid timing in extension block
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
                   ` (3 preceding siblings ...)
  2021-03-06 19:54 ` [PATCH v2 04/19] common: edid: extract code for detailed timing search Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-03-06 19:54 ` [PATCH v2 06/19] video: sunxi: Use DW-HDMI hpd function Jernej Skrabec
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

One of my monitors have only 4k at 60 timing in base EDID block which is
out of range for devices with HDMI 1.4. It turns out that it has
additional detailed timings in CTA-861 Extension Block and two of them
are appropriate for HDMI 1.4.

Add additional search for valid detailed timing in extension block.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 common/edid.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/common/edid.c b/common/edid.c
index a6c875d9c8e8..14d8836c360e 100644
--- a/common/edid.c
+++ b/common/edid.c
@@ -220,6 +220,24 @@ int edid_get_timing_validate(u8 *buf, int buf_size,
 	/* Look for detailed timing in base EDID */
 	found = edid_find_valid_timing(edid->monitor_details.descriptor, 4,
 				       timing, mode_valid, mode_valid_priv);
+
+	/* Look for detailed timing in CTA-861 Extension Block */
+	if (!found && edid->extension_flag && buf_size >= EDID_EXT_SIZE) {
+		struct edid_cea861_info *info =
+			(struct edid_cea861_info *)(buf + sizeof(*edid));
+
+		if (info->extension_tag == EDID_CEA861_EXTENSION_TAG) {
+			int count = EDID_CEA861_DTD_COUNT(*info);
+			int offset = info->dtd_offset;
+			int size = count * sizeof(struct edid_detailed_timing);
+
+			if (offset >= 4 && offset + size < EDID_SIZE)
+				found = edid_find_valid_timing(
+					(u8*)info + offset, count, timing,
+					mode_valid, mode_valid_priv);
+		}
+	}
+
 	if (!found)
 		return -EINVAL;
 
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 06/19] video: sunxi: Use DW-HDMI hpd function
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
                   ` (4 preceding siblings ...)
  2021-03-06 19:54 ` [PATCH v2 05/19] common: edid: Search for valid timing in extension block Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-03-07  1:30   ` Andre Przywara
  2021-03-06 19:54 ` [PATCH v2 07/19] video: sunxi: Remove check for ddc-i2c-bus property Jernej Skrabec
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

It turns out that there are two ways how hot plug detection can be done.
One is standard way for DW HDMI controller - checking bit 2 in 0x3004
register. Another way is applicable only to Allwinner custom PHY - by
checking bit 19 in register 0x10038. Both method are equally good as far
as we know.

Use standard method in order to reduce amount of custom code.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 drivers/video/sunxi/sunxi_dw_hdmi.c | 34 +++++------------------------
 1 file changed, 6 insertions(+), 28 deletions(-)

diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c
index e3811a2ec15f..37e78ff24111 100644
--- a/drivers/video/sunxi/sunxi_dw_hdmi.c
+++ b/drivers/video/sunxi/sunxi_dw_hdmi.c
@@ -114,28 +114,6 @@ static void sunxi_dw_hdmi_phy_init(void)
 	writel(0x42494E47, &phy->unscramble);
 }
 
-static int sunxi_dw_hdmi_get_plug_in_status(void)
-{
-	struct sunxi_hdmi_phy * const phy =
-		(struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS);
-
-	return !!(readl(&phy->status) & (1 << 19));
-}
-
-static int sunxi_dw_hdmi_wait_for_hpd(void)
-{
-	ulong start;
-
-	start = get_timer(0);
-	do {
-		if (sunxi_dw_hdmi_get_plug_in_status())
-			return 0;
-		udelay(100);
-	} while (get_timer(start) < 300);
-
-	return -1;
-}
-
 static void sunxi_dw_hdmi_phy_set(uint clock, int phy_div)
 {
 	struct sunxi_hdmi_phy * const phy =
@@ -370,12 +348,6 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev)
 
 	sunxi_dw_hdmi_phy_init();
 
-	ret = sunxi_dw_hdmi_wait_for_hpd();
-	if (ret < 0) {
-		debug("hdmi can not get hpd signal\n");
-		return -1;
-	}
-
 	priv->hdmi.ioaddr = SUNXI_HDMI_BASE;
 	priv->hdmi.i2c_clk_high = 0xd8;
 	priv->hdmi.i2c_clk_low = 0xfe;
@@ -383,6 +355,12 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev)
 	priv->hdmi.phy_set = sunxi_dw_hdmi_phy_cfg;
 	priv->mux = uc_plat->source_id;
 
+	ret = dw_hdmi_phy_wait_for_hpd(&priv->hdmi);
+	if (ret < 0) {
+		debug("hdmi can not get hpd signal\n");
+		return -1;
+	}
+
 	uclass_get_device_by_phandle(UCLASS_I2C, dev, "ddc-i2c-bus",
 				     &priv->hdmi.ddc_bus);
 
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 07/19] video: sunxi: Remove check for ddc-i2c-bus property
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
                   ` (5 preceding siblings ...)
  2021-03-06 19:54 ` [PATCH v2 06/19] video: sunxi: Use DW-HDMI hpd function Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-03-06 19:54 ` [PATCH v2 08/19] video: sunxi: Remove TV probe from DE2 Jernej Skrabec
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

No Allwinner board with DW-HDMI controller use separate I2C bus for
EDID read. Remove that check.

Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 drivers/video/sunxi/sunxi_dw_hdmi.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c
index 37e78ff24111..6d2bc206fc2c 100644
--- a/drivers/video/sunxi/sunxi_dw_hdmi.c
+++ b/drivers/video/sunxi/sunxi_dw_hdmi.c
@@ -361,9 +361,6 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev)
 		return -1;
 	}
 
-	uclass_get_device_by_phandle(UCLASS_I2C, dev, "ddc-i2c-bus",
-				     &priv->hdmi.ddc_bus);
-
 	dw_hdmi_init(&priv->hdmi);
 
 	return 0;
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 08/19] video: sunxi: Remove TV probe from DE2
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
                   ` (6 preceding siblings ...)
  2021-03-06 19:54 ` [PATCH v2 07/19] video: sunxi: Remove check for ddc-i2c-bus property Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-03-07  1:31   ` Andre Przywara
  2021-03-06 19:54 ` [PATCH v2 09/19] video: sunxi: de2: switch to public uclass functions Jernej Skrabec
                   ` (10 subsequent siblings)
  18 siblings, 1 reply; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

TV driver was never fully implemented. Remove search for it from DE2
driver.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 drivers/video/sunxi/sunxi_de2.c | 15 +--------------
 1 file changed, 1 insertion(+), 14 deletions(-)

diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c
index a3e21aa5f13e..6b836a011944 100644
--- a/drivers/video/sunxi/sunxi_de2.c
+++ b/drivers/video/sunxi/sunxi_de2.c
@@ -281,20 +281,7 @@ static int sunxi_de2_probe(struct udevice *dev)
 
 	debug("%s: hdmi display not found (ret=%d)\n", __func__, ret);
 
-	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
-					"sunxi_tve", &disp);
-	if (ret) {
-		debug("%s: tv not found (ret=%d)\n", __func__, ret);
-		return ret;
-	}
-
-	ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, 1, true);
-	if (ret)
-		return ret;
-
-	video_set_flush_dcache(dev, 1);
-
-	return 0;
+	return -ENODEV;
 }
 
 static int sunxi_de2_bind(struct udevice *dev)
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 09/19] video: sunxi: de2: switch to public uclass functions
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
                   ` (7 preceding siblings ...)
  2021-03-06 19:54 ` [PATCH v2 08/19] video: sunxi: Remove TV probe from DE2 Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-03-07  1:32   ` Andre Przywara
  2021-03-06 19:54 ` [PATCH v2 10/19] video: sunxi: dw-hdmi: probe driver by compatible Jernej Skrabec
                   ` (9 subsequent siblings)
  18 siblings, 1 reply; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

Currently DE2 driver uses functions which are defined in internal
headers. They are not meant to be used outside of uclass framework.
Switch DE2 driver to public ones. This has additional benefit that
device_probe doesn't need to be called manually.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 drivers/video/sunxi/sunxi_de2.c | 29 ++++++++++-------------------
 1 file changed, 10 insertions(+), 19 deletions(-)

diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c
index 6b836a011944..e02d359cd259 100644
--- a/drivers/video/sunxi/sunxi_de2.c
+++ b/drivers/video/sunxi/sunxi_de2.c
@@ -19,8 +19,6 @@
 #include <asm/io.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/display2.h>
-#include <dm/device-internal.h>
-#include <dm/uclass-internal.h>
 #include <linux/bitops.h>
 #include "simplefb_common.h"
 
@@ -198,13 +196,6 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase,
 
 	disp_uc_plat->source_id = mux;
 
-	ret = device_probe(disp);
-	if (ret) {
-		debug("%s: device '%s' display won't probe (ret=%d)\n",
-		      __func__, dev->name, ret);
-		return ret;
-	}
-
 	ret = display_read_timing(disp, &timing);
 	if (ret) {
 		debug("%s: Failed to read timings\n", __func__);
@@ -245,8 +236,8 @@ static int sunxi_de2_probe(struct udevice *dev)
 	if (!(gd->flags & GD_FLG_RELOC))
 		return 0;
 
-	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
-					 "sunxi_lcd", &disp);
+	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
+					  DM_DRIVER_GET(sunxi_lcd), &disp);
 	if (!ret) {
 		int mux;
 
@@ -262,8 +253,8 @@ static int sunxi_de2_probe(struct udevice *dev)
 
 	debug("%s: lcd display not found (ret=%d)\n", __func__, ret);
 
-	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
-					 "sunxi_dw_hdmi", &disp);
+	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
+					  DM_DRIVER_GET(sunxi_dw_hdmi), &disp);
 	if (!ret) {
 		int mux;
 		if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
@@ -332,8 +323,8 @@ int sunxi_simplefb_setup(void *blob)
 		mux = 1;
 
 	/* Skip simplefb setting if DE2 / HDMI is not present */
-	ret = uclass_find_device_by_name(UCLASS_VIDEO,
-					 "sunxi_de2", &de2);
+	ret = uclass_get_device_by_driver(UCLASS_VIDEO,
+					  DM_DRIVER_GET(sunxi_de2), &de2);
 	if (ret) {
 		debug("DE2 not present\n");
 		return 0;
@@ -342,8 +333,8 @@ int sunxi_simplefb_setup(void *blob)
 		return 0;
 	}
 
-	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
-					 "sunxi_dw_hdmi", &hdmi);
+	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
+					  DM_DRIVER_GET(sunxi_dw_hdmi), &hdmi);
 	if (ret) {
 		debug("HDMI not present\n");
 	} else if (device_active(hdmi)) {
@@ -355,8 +346,8 @@ int sunxi_simplefb_setup(void *blob)
 		debug("HDMI present but not probed\n");
 	}
 
-	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
-					 "sunxi_lcd", &lcd);
+	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
+					  DM_DRIVER_GET(sunxi_lcd), &lcd);
 	if (ret)
 		debug("LCD not present\n");
 	else if (device_active(lcd))
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 10/19] video: sunxi: dw-hdmi: probe driver by compatible
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
                   ` (8 preceding siblings ...)
  2021-03-06 19:54 ` [PATCH v2 09/19] video: sunxi: de2: switch to public uclass functions Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-03-07  1:33   ` Andre Przywara
  2021-03-06 19:54 ` [PATCH v2 11/19] video: sunxi: dw-hdmi: read address from DT node Jernej Skrabec
                   ` (8 subsequent siblings)
  18 siblings, 1 reply; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

Currently sunxi dw-hdmi driver is probed unconditionally, even if there
is no such device.

Switch driver to probing via compatible string. This brings many
benefits - driver can read DT node and allows driver to be always
enabled.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 drivers/video/sunxi/sunxi_dw_hdmi.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c
index 6d2bc206fc2c..6f77b2a43b40 100644
--- a/drivers/video/sunxi/sunxi_dw_hdmi.c
+++ b/drivers/video/sunxi/sunxi_dw_hdmi.c
@@ -372,14 +372,16 @@ static const struct dm_display_ops sunxi_dw_hdmi_ops = {
 	.mode_valid = sunxi_dw_hdmi_mode_valid,
 };
 
+static const struct udevice_id sunxi_dw_hdmi_ids[] = {
+	{ .compatible = "allwinner,sun8i-a83t-dw-hdmi" },
+	{ }
+};
+
 U_BOOT_DRIVER(sunxi_dw_hdmi) = {
 	.name	= "sunxi_dw_hdmi",
 	.id	= UCLASS_DISPLAY,
+	.of_match = sunxi_dw_hdmi_ids,
 	.ops	= &sunxi_dw_hdmi_ops,
 	.probe	= sunxi_dw_hdmi_probe,
 	.priv_auto	= sizeof(struct sunxi_dw_hdmi_priv),
 };
-
-U_BOOT_DRVINFO(sunxi_dw_hdmi) = {
-	.name = "sunxi_dw_hdmi"
-};
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 11/19] video: sunxi: dw-hdmi: read address from DT node
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
                   ` (9 preceding siblings ...)
  2021-03-06 19:54 ` [PATCH v2 10/19] video: sunxi: dw-hdmi: probe driver by compatible Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-04-06  1:09   ` Andre Przywara
  2021-03-06 19:54 ` [PATCH v2 12/19] video: sunxi: de2: switch to DT probing Jernej Skrabec
                   ` (7 subsequent siblings)
  18 siblings, 1 reply; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

Currently HDMI controller MMIO address is hardcoded. Change that so
address is read from DT node. That will make adding support for new
variants a bit easier.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 drivers/video/sunxi/sunxi_dw_hdmi.c | 38 ++++++++++++++++++-----------
 1 file changed, 24 insertions(+), 14 deletions(-)

diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c
index 6f77b2a43b40..0744954fa15f 100644
--- a/drivers/video/sunxi/sunxi_dw_hdmi.c
+++ b/drivers/video/sunxi/sunxi_dw_hdmi.c
@@ -57,10 +57,10 @@ static int sunxi_dw_hdmi_get_divider(uint clock)
 		return 1;
 }
 
-static void sunxi_dw_hdmi_phy_init(void)
+static void sunxi_dw_hdmi_phy_init(struct dw_hdmi *hdmi)
 {
 	struct sunxi_hdmi_phy * const phy =
-		(struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS);
+		(struct sunxi_hdmi_phy *)(hdmi->ioaddr + HDMI_PHY_OFFS);
 	unsigned long tmo;
 	u32 tmp;
 
@@ -114,10 +114,10 @@ static void sunxi_dw_hdmi_phy_init(void)
 	writel(0x42494E47, &phy->unscramble);
 }
 
-static void sunxi_dw_hdmi_phy_set(uint clock, int phy_div)
+static void sunxi_dw_hdmi_phy_set(struct dw_hdmi *hdmi, uint clock, int phy_div)
 {
 	struct sunxi_hdmi_phy * const phy =
-		(struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS);
+		(struct sunxi_hdmi_phy *)(hdmi->ioaddr + HDMI_PHY_OFFS);
 	int div = sunxi_dw_hdmi_get_divider(clock);
 	u32 tmp;
 
@@ -271,7 +271,7 @@ static int sunxi_dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock)
 	int phy_div;
 
 	sunxi_dw_hdmi_pll_set(mpixelclock / 1000, &phy_div);
-	sunxi_dw_hdmi_phy_set(mpixelclock, phy_div);
+	sunxi_dw_hdmi_phy_set(hdmi, mpixelclock, phy_div);
 
 	return 0;
 }
@@ -292,9 +292,9 @@ static bool sunxi_dw_hdmi_mode_valid(struct udevice *dev,
 static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp,
 				const struct display_timing *edid)
 {
-	struct sunxi_hdmi_phy * const phy =
-		(struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS);
 	struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev);
+	struct sunxi_hdmi_phy * const phy =
+		(struct sunxi_hdmi_phy *)(priv->hdmi.ioaddr + HDMI_PHY_OFFS);
 	int ret;
 
 	ret = dw_hdmi_enable(&priv->hdmi, edid);
@@ -316,12 +316,26 @@ static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp,
 	 * again or othwerwise BSP driver won't work. Dummy read is
 	 * needed or otherwise last write doesn't get written correctly.
 	 */
-	(void)readb(SUNXI_HDMI_BASE);
+	(void)readb(priv->hdmi.ioaddr);
 	writel(0, &phy->unscramble);
 
 	return 0;
 }
 
+static int sunxi_dw_hdmi_of_to_plat(struct udevice *dev)
+{
+	struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev);
+	struct dw_hdmi *hdmi = &priv->hdmi;
+
+	hdmi->ioaddr = (ulong)dev_read_addr(dev);
+	hdmi->i2c_clk_high = 0xd8;
+	hdmi->i2c_clk_low = 0xfe;
+	hdmi->reg_io_width = 1;
+	hdmi->phy_set = sunxi_dw_hdmi_phy_cfg;
+
+	return 0;
+}
+
 static int sunxi_dw_hdmi_probe(struct udevice *dev)
 {
 	struct display_plat *uc_plat = dev_get_uclass_plat(dev);
@@ -346,13 +360,8 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev)
 	/* Clock on */
 	setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
 
-	sunxi_dw_hdmi_phy_init();
+	sunxi_dw_hdmi_phy_init(&priv->hdmi);
 
-	priv->hdmi.ioaddr = SUNXI_HDMI_BASE;
-	priv->hdmi.i2c_clk_high = 0xd8;
-	priv->hdmi.i2c_clk_low = 0xfe;
-	priv->hdmi.reg_io_width = 1;
-	priv->hdmi.phy_set = sunxi_dw_hdmi_phy_cfg;
 	priv->mux = uc_plat->source_id;
 
 	ret = dw_hdmi_phy_wait_for_hpd(&priv->hdmi);
@@ -382,6 +391,7 @@ U_BOOT_DRIVER(sunxi_dw_hdmi) = {
 	.id	= UCLASS_DISPLAY,
 	.of_match = sunxi_dw_hdmi_ids,
 	.ops	= &sunxi_dw_hdmi_ops,
+	.of_to_plat = sunxi_dw_hdmi_of_to_plat,
 	.probe	= sunxi_dw_hdmi_probe,
 	.priv_auto	= sizeof(struct sunxi_dw_hdmi_priv),
 };
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 12/19] video: sunxi: de2: switch to DT probing
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
                   ` (10 preceding siblings ...)
  2021-03-06 19:54 ` [PATCH v2 11/19] video: sunxi: dw-hdmi: read address from DT node Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-04-06  1:09   ` Andre Przywara
  2021-03-06 19:54 ` [PATCH v2 13/19] video: sunxi: de2: read address from DT node Jernej Skrabec
                   ` (6 subsequent siblings)
  18 siblings, 1 reply; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

Currently DE2 driver is probed via driver info. Switch probing to device
tree compatible string method.

Display is now searched via driver name which has same limitation as
previous method. This can be improved only when all drivers in chain are
probed via device tree compatible strings.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 drivers/video/sunxi/sunxi_de2.c | 88 +++++++++++++++++++--------------
 1 file changed, 52 insertions(+), 36 deletions(-)

diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c
index e02d359cd259..81576e45e9ef 100644
--- a/drivers/video/sunxi/sunxi_de2.c
+++ b/drivers/video/sunxi/sunxi_de2.c
@@ -31,6 +31,11 @@ enum {
 	LCD_MAX_LOG2_BPP	= VIDEO_BPP32,
 };
 
+struct sunxi_de2_data {
+	int id;
+	const char *disp_drv_name;
+};
+
 static void sunxi_de2_composer_init(void)
 {
 	struct sunxi_ccm_reg * const ccm =
@@ -228,51 +233,34 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase,
 
 static int sunxi_de2_probe(struct udevice *dev)
 {
+	const struct sunxi_de2_data *data =
+		(const struct sunxi_de2_data *)dev_get_driver_data(dev);
 	struct video_uc_plat *plat = dev_get_uclass_plat(dev);
 	struct udevice *disp;
-	int ret;
+	int ret, index = 0;
 
 	/* Before relocation we don't need to do anything */
 	if (!(gd->flags & GD_FLG_RELOC))
 		return 0;
 
-	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
-					  DM_DRIVER_GET(sunxi_lcd), &disp);
-	if (!ret) {
-		int mux;
+	while (!(ret = uclass_get_device(UCLASS_DISPLAY, index++, &disp))) {
+		if (strcmp(disp->driver->name, data->disp_drv_name))
+			continue;
 
-		mux = 0;
+		ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp,
+				     data->id, false);
+		if (ret)
+			return ret;
 
-		ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux,
-				     false);
-		if (!ret) {
-			video_set_flush_dcache(dev, 1);
-			return 0;
-		}
-	}
-
-	debug("%s: lcd display not found (ret=%d)\n", __func__, ret);
-
-	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
-					  DM_DRIVER_GET(sunxi_dw_hdmi), &disp);
-	if (!ret) {
-		int mux;
-		if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
-			mux = 0;
-		else
-			mux = 1;
+		video_set_flush_dcache(dev, 1);
 
-		ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux,
-				     false);
-		if (!ret) {
-			video_set_flush_dcache(dev, 1);
-			return 0;
-		}
+		return 0;
 	}
 
-	debug("%s: hdmi display not found (ret=%d)\n", __func__, ret);
+	debug("%s: %s not found (ret=%d)\n", __func__,
+	      data->disp_drv_name, ret);
 
-	return -ENODEV;
+	return ret;
 }
 
 static int sunxi_de2_bind(struct udevice *dev)
@@ -285,22 +273,50 @@ static int sunxi_de2_bind(struct udevice *dev)
 	return 0;
 }
 
+const struct sunxi_de2_data h3_mixer_0 = {
+	.id = 0,
+	.disp_drv_name = "sunxi_dw_hdmi",
+};
+
+const struct sunxi_de2_data a64_mixer_0 = {
+	.id = 0,
+	.disp_drv_name = "sunxi_lcd",
+};
+
+const struct sunxi_de2_data a64_mixer_1 = {
+	.id = 1,
+	.disp_drv_name = "sunxi_dw_hdmi",
+};
+
+static const struct udevice_id sunxi_de2_ids[] = {
+	{
+		.compatible = "allwinner,sun8i-h3-de2-mixer-0",
+		.data = (ulong)&h3_mixer_0,
+	},
+	{
+		.compatible = "allwinner,sun50i-a64-de2-mixer-0",
+		.data = (ulong)&a64_mixer_0,
+	},
+	{
+		.compatible = "allwinner,sun50i-a64-de2-mixer-1",
+		.data = (ulong)&a64_mixer_1,
+	},
+	{ }
+};
+
 static const struct video_ops sunxi_de2_ops = {
 };
 
 U_BOOT_DRIVER(sunxi_de2) = {
 	.name	= "sunxi_de2",
 	.id	= UCLASS_VIDEO,
+	.of_match = sunxi_de2_ids,
 	.ops	= &sunxi_de2_ops,
 	.bind	= sunxi_de2_bind,
 	.probe	= sunxi_de2_probe,
 	.flags	= DM_FLAG_PRE_RELOC,
 };
 
-U_BOOT_DRVINFO(sunxi_de2) = {
-	.name = "sunxi_de2"
-};
-
 /*
  * Simplefb support.
  */
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 13/19] video: sunxi: de2: read address from DT node
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
                   ` (11 preceding siblings ...)
  2021-03-06 19:54 ` [PATCH v2 12/19] video: sunxi: de2: switch to DT probing Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-04-06  1:10   ` Andre Przywara
  2021-03-06 19:54 ` [PATCH v2 14/19] clk: sunxi: Add DE2 and HDMI clocks to H3 and A64 Jernej Skrabec
                   ` (5 subsequent siblings)
  18 siblings, 1 reply; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

Currently DE2 uses hardcoded address based on SoC for which U-Boot is
built. Read it from DT instead so there is no need to specify it when
support for new SoC is added.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 drivers/video/sunxi/sunxi_de2.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c
index 81576e45e9ef..f6c8ca075aba 100644
--- a/drivers/video/sunxi/sunxi_de2.c
+++ b/drivers/video/sunxi/sunxi_de2.c
@@ -64,11 +64,10 @@ static void sunxi_de2_composer_init(void)
 	setbits_le32(&ccm->de_clk_cfg, CCM_DE2_CTRL_GATE);
 }
 
-static void sunxi_de2_mode_set(int mux, const struct display_timing *mode,
+static void sunxi_de2_mode_set(ulong de_mux_base, int mux,
+			       const struct display_timing *mode,
 			       int bpp, ulong address, bool is_composite)
 {
-	ulong de_mux_base = (mux == 0) ?
-			    SUNXI_DE2_MUX0_BASE : SUNXI_DE2_MUX1_BASE;
 	struct de_clk * const de_clk_regs =
 		(struct de_clk *)(SUNXI_DE2_BASE);
 	struct de_glb * const de_glb_regs =
@@ -208,7 +207,8 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase,
 	}
 
 	sunxi_de2_composer_init();
-	sunxi_de2_mode_set(mux, &timing, 1 << l2bpp, fbbase, is_composite);
+	sunxi_de2_mode_set((ulong)dev_read_addr(dev), mux, &timing,
+			   1 << l2bpp, fbbase, is_composite);
 
 	ret = display_enable(disp, 1 << l2bpp, &timing);
 	if (ret) {
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 14/19] clk: sunxi: Add DE2 and HDMI clocks to H3 and A64
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
                   ` (12 preceding siblings ...)
  2021-03-06 19:54 ` [PATCH v2 13/19] video: sunxi: de2: read address from DT node Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-03-08  8:00   ` Jagan Teki
  2021-03-06 19:54 ` [PATCH v2 15/19] clk: sunxi: add DE2 clock driver Jernej Skrabec
                   ` (4 subsequent siblings)
  18 siblings, 1 reply; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

These clocks and resets are needed for video drivers.

Cc: Lukasz Majewski <lukma@denx.de>
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 drivers/clk/sunxi/clk_a64.c | 12 ++++++++++++
 drivers/clk/sunxi/clk_h3.c  | 12 ++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/drivers/clk/sunxi/clk_a64.c b/drivers/clk/sunxi/clk_a64.c
index 0553ffa4399a..28131240652f 100644
--- a/drivers/clk/sunxi/clk_a64.c
+++ b/drivers/clk/sunxi/clk_a64.c
@@ -26,6 +26,9 @@ static const struct ccu_clk_gate a64_gates[] = {
 	[CLK_BUS_OHCI0]		= GATE(0x060, BIT(28)),
 	[CLK_BUS_OHCI1]		= GATE(0x060, BIT(29)),
 
+	[CLK_BUS_HDMI]		= GATE(0x064, BIT(11)),
+	[CLK_BUS_DE]		= GATE(0x064, BIT(12)),
+
 	[CLK_BUS_UART0]		= GATE(0x06c, BIT(16)),
 	[CLK_BUS_UART1]		= GATE(0x06c, BIT(17)),
 	[CLK_BUS_UART2]		= GATE(0x06c, BIT(18)),
@@ -41,6 +44,11 @@ static const struct ccu_clk_gate a64_gates[] = {
 	[CLK_USB_HSIC_12M]	= GATE(0x0cc, BIT(11)),
 	[CLK_USB_OHCI0]		= GATE(0x0cc, BIT(16)),
 	[CLK_USB_OHCI1]		= GATE(0x0cc, BIT(17)),
+
+	[CLK_DE]		= GATE(0x104, BIT(31)),
+
+	[CLK_HDMI]		= GATE(0x150, BIT(31)),
+	[CLK_HDMI_DDC]		= GATE(0x154, BIT(31)),
 };
 
 static const struct ccu_reset a64_resets[] = {
@@ -60,6 +68,10 @@ static const struct ccu_reset a64_resets[] = {
 	[RST_BUS_OHCI0]         = RESET(0x2c0, BIT(28)),
 	[RST_BUS_OHCI1]         = RESET(0x2c0, BIT(29)),
 
+	[RST_BUS_HDMI0]		= RESET(0x2c4, BIT(10)),
+	[RST_BUS_HDMI1]		= RESET(0x2c4, BIT(11)),
+	[RST_BUS_DE]		= RESET(0x2c4, BIT(12)),
+
 	[RST_BUS_UART0]		= RESET(0x2d8, BIT(16)),
 	[RST_BUS_UART1]		= RESET(0x2d8, BIT(17)),
 	[RST_BUS_UART2]		= RESET(0x2d8, BIT(18)),
diff --git a/drivers/clk/sunxi/clk_h3.c b/drivers/clk/sunxi/clk_h3.c
index f81633b92d5a..806a35b37435 100644
--- a/drivers/clk/sunxi/clk_h3.c
+++ b/drivers/clk/sunxi/clk_h3.c
@@ -30,6 +30,9 @@ static struct ccu_clk_gate h3_gates[] = {
 	[CLK_BUS_OHCI2]		= GATE(0x060, BIT(30)),
 	[CLK_BUS_OHCI3]		= GATE(0x060, BIT(31)),
 
+	[CLK_BUS_HDMI]		= GATE(0x064, BIT(11)),
+	[CLK_BUS_DE]		= GATE(0x064, BIT(12)),
+
 	[CLK_BUS_UART0]		= GATE(0x06c, BIT(16)),
 	[CLK_BUS_UART1]		= GATE(0x06c, BIT(17)),
 	[CLK_BUS_UART2]		= GATE(0x06c, BIT(18)),
@@ -48,6 +51,11 @@ static struct ccu_clk_gate h3_gates[] = {
 	[CLK_USB_OHCI1]		= GATE(0x0cc, BIT(17)),
 	[CLK_USB_OHCI2]		= GATE(0x0cc, BIT(18)),
 	[CLK_USB_OHCI3]		= GATE(0x0cc, BIT(19)),
+
+	[CLK_DE]		= GATE(0x104, BIT(31)),
+
+	[CLK_HDMI]		= GATE(0x150, BIT(31)),
+	[CLK_HDMI_DDC]		= GATE(0x154, BIT(31)),
 };
 
 static struct ccu_reset h3_resets[] = {
@@ -72,6 +80,10 @@ static struct ccu_reset h3_resets[] = {
 	[RST_BUS_OHCI2]		= RESET(0x2c0, BIT(30)),
 	[RST_BUS_OHCI3]		= RESET(0x2c0, BIT(31)),
 
+	[RST_BUS_HDMI0]		= RESET(0x2c4, BIT(10)),
+	[RST_BUS_HDMI1]		= RESET(0x2c4, BIT(11)),
+	[RST_BUS_DE]		= RESET(0x2c4, BIT(12)),
+
 	[RST_BUS_EPHY]		= RESET(0x2c8, BIT(2)),
 
 	[RST_BUS_UART0]		= RESET(0x2d8, BIT(16)),
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 15/19] clk: sunxi: add DE2 clock driver
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
                   ` (13 preceding siblings ...)
  2021-03-06 19:54 ` [PATCH v2 14/19] clk: sunxi: Add DE2 and HDMI clocks to H3 and A64 Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-03-08  7:59   ` Jagan Teki
  2021-03-06 19:54 ` [PATCH v2 16/19] video: sunxi: de2: switch clock setup to DM model Jernej Skrabec
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

Video driver currently manages clocks and resets by directly writing to
registers. This is already a bit messy because each SoC has some
specifics. It's much better to implement proper clock and reset driver
which takes information from device tree file.

Note that this driver is not perfect yet. It still sets PLL and parent
by hand. Sunxi clock framework still doesn't know how to set parents or
rates. However, this is already big step in right direction.

Cc: Lukasz Majewski <lukma@denx.de>
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 drivers/clk/sunxi/Kconfig   |  5 +++
 drivers/clk/sunxi/Makefile  |  1 +
 drivers/clk/sunxi/clk_de2.c | 85 +++++++++++++++++++++++++++++++++++++
 3 files changed, 91 insertions(+)
 create mode 100644 drivers/clk/sunxi/clk_de2.c

diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig
index bf084fa7a84a..6c96affb1f87 100644
--- a/drivers/clk/sunxi/Kconfig
+++ b/drivers/clk/sunxi/Kconfig
@@ -44,6 +44,11 @@ config CLK_SUN8I_A83T
 	  This enables common clock driver support for platforms based
 	  on Allwinner A83T SoC.
 
+config CLK_SUN8I_DE2
+	bool "Clock driver for Allwinner Display Engine 2 and 3"
+	help
+	  This enables common clock driver support for Display Engine 2 and 3.
+
 config CLK_SUN8I_R40
 	bool "Clock driver for Allwinner R40"
 	default MACH_SUN8I_R40
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index 0dfc0593fb1c..620ff96ac6f5 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_CLK_SUN5I_A10S) += clk_a10s.o
 obj-$(CONFIG_CLK_SUN6I_A31) += clk_a31.o
 obj-$(CONFIG_CLK_SUN8I_A23) += clk_a23.o
 obj-$(CONFIG_CLK_SUN8I_A83T) += clk_a83t.o
+obj-$(CONFIG_CLK_SUN8I_DE2) += clk_de2.o
 obj-$(CONFIG_CLK_SUN8I_R40) += clk_r40.o
 obj-$(CONFIG_CLK_SUN8I_V3S) += clk_v3s.o
 obj-$(CONFIG_CLK_SUN9I_A80) += clk_a80.o
diff --git a/drivers/clk/sunxi/clk_de2.c b/drivers/clk/sunxi/clk_de2.c
new file mode 100644
index 000000000000..b8c45404c1b6
--- /dev/null
+++ b/drivers/clk/sunxi/clk_de2.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2021 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/arch/ccu.h>
+#include <asm/arch/clock.h>
+#include <asm/io.h>
+#include <dt-bindings/clock/sun8i-de2.h>
+#include <dt-bindings/reset/sun8i-de2.h>
+#include <linux/bitops.h>
+
+static struct ccu_clk_gate de2_gates[] = {
+	[CLK_MIXER0]		= GATE(0x00, BIT(0)),
+	[CLK_MIXER1]		= GATE(0x00, BIT(1)),
+	[CLK_WB]		= GATE(0x00, BIT(2)),
+
+	[CLK_BUS_MIXER0]	= GATE(0x04, BIT(0)),
+	[CLK_BUS_MIXER1]	= GATE(0x04, BIT(1)),
+	[CLK_BUS_WB]		= GATE(0x04, BIT(2)),
+};
+
+static struct ccu_reset de2_resets[] = {
+	[RST_MIXER0]		= RESET(0x08, BIT(0)),
+	[RST_MIXER1]		= RESET(0x08, BIT(1)),
+	[RST_WB]		= RESET(0x08, BIT(2)),
+};
+
+static const struct ccu_desc de2_ccu_desc = {
+	.gates = de2_gates,
+	.resets = de2_resets,
+};
+
+static int de2_clk_probe(struct udevice *dev)
+{
+	struct sunxi_ccm_reg * const ccm =
+		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+	u32 val;
+
+	if (device_is_compatible(dev_get_parent(dev),
+				 "allwinner,sun50i-a64-de2")) {
+		/* set SRAM for video use */
+		val = readl(SUNXI_SRAMC_BASE + 0x04);
+		val &= ~(0x01 << 24);
+		writel(val, SUNXI_SRAMC_BASE + 0x04);
+	}
+
+	/* clock driver doesn't know how to set rate or parent yet */
+	clock_set_pll10(432000000);
+
+	/* Set DE parent to pll10 */
+	clrsetbits_le32(&ccm->de_clk_cfg, CCM_DE2_CTRL_PLL_MASK,
+			CCM_DE2_CTRL_PLL10);
+
+	return sunxi_clk_probe(dev);
+}
+
+static int de2_clk_bind(struct udevice *dev)
+{
+	return sunxi_reset_bind(dev, ARRAY_SIZE(de2_resets));
+}
+
+static const struct udevice_id de2_ccu_ids[] = {
+	{ .compatible = "allwinner,sun8i-h3-de2-clk",
+	  .data = (ulong)&de2_ccu_desc },
+	{ .compatible = "allwinner,sun50i-a64-de2-clk",
+	  .data = (ulong)&de2_ccu_desc },
+	{ .compatible = "allwinner,sun50i-h5-de2-clk",
+	  .data = (ulong)&de2_ccu_desc },
+	{ }
+};
+
+U_BOOT_DRIVER(clk_sun8i_de2) = {
+	.name		= "sun8i_de2_ccu",
+	.id		= UCLASS_CLK,
+	.of_match	= de2_ccu_ids,
+	.priv_auto	= sizeof(struct ccu_priv),
+	.ops		= &sunxi_clk_ops,
+	.probe		= de2_clk_probe,
+	.bind		= de2_clk_bind,
+};
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 16/19] video: sunxi: de2: switch clock setup to DM model
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
                   ` (14 preceding siblings ...)
  2021-03-06 19:54 ` [PATCH v2 15/19] clk: sunxi: add DE2 clock driver Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-03-08  8:02   ` Jagan Teki
  2021-03-06 19:54 ` [PATCH v2 17/19] video: dw-hdmi: modify phy init callback to include full timings Jernej Skrabec
                   ` (2 subsequent siblings)
  18 siblings, 1 reply; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

Now that proper DM clock and reset driver exists for Display Engine 2
and 3, remove all clock and reset related code and use appropriate
framework instead.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 arch/arm/mach-sunxi/Kconfig     |  1 +
 drivers/video/sunxi/sunxi_de2.c | 67 +++++++++++----------------------
 2 files changed, 23 insertions(+), 45 deletions(-)

diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 9149196b223e..34ef1f4b030f 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -970,6 +970,7 @@ config SUNXI_DE2
 config VIDEO_DE2
 	bool "Display Engine 2 video driver"
 	depends on SUNXI_DE2
+	select CLK_SUN8I_DE2
 	select DM_VIDEO
 	select DISPLAY
 	select VIDEO_DW_HDMI
diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c
index f6c8ca075aba..cee9b46b1259 100644
--- a/drivers/video/sunxi/sunxi_de2.c
+++ b/drivers/video/sunxi/sunxi_de2.c
@@ -6,6 +6,7 @@
  */
 
 #include <common.h>
+#include <clk.h>
 #include <display.h>
 #include <dm.h>
 #include <edid.h>
@@ -14,10 +15,10 @@
 #include <fdt_support.h>
 #include <log.h>
 #include <part.h>
+#include <reset.h>
 #include <video.h>
 #include <asm/global_data.h>
 #include <asm/io.h>
-#include <asm/arch/clock.h>
 #include <asm/arch/display2.h>
 #include <linux/bitops.h>
 #include "simplefb_common.h"
@@ -36,40 +37,10 @@ struct sunxi_de2_data {
 	const char *disp_drv_name;
 };
 
-static void sunxi_de2_composer_init(void)
-{
-	struct sunxi_ccm_reg * const ccm =
-		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
-
-#ifdef CONFIG_MACH_SUN50I
-	u32 reg_value;
-
-	/* set SRAM for video use (A64 only) */
-	reg_value = readl(SUNXI_SRAMC_BASE + 0x04);
-	reg_value &= ~(0x01 << 24);
-	writel(reg_value, SUNXI_SRAMC_BASE + 0x04);
-#endif
-
-	clock_set_pll10(432000000);
-
-	/* Set DE parent to pll10 */
-	clrsetbits_le32(&ccm->de_clk_cfg, CCM_DE2_CTRL_PLL_MASK,
-			CCM_DE2_CTRL_PLL10);
-
-	/* Set ahb gating to pass */
-	setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_DE);
-	setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_DE);
-
-	/* Clock on */
-	setbits_le32(&ccm->de_clk_cfg, CCM_DE2_CTRL_GATE);
-}
-
-static void sunxi_de2_mode_set(ulong de_mux_base, int mux,
+static void sunxi_de2_mode_set(ulong de_mux_base,
 			       const struct display_timing *mode,
 			       int bpp, ulong address, bool is_composite)
 {
-	struct de_clk * const de_clk_regs =
-		(struct de_clk *)(SUNXI_DE2_BASE);
 	struct de_glb * const de_glb_regs =
 		(struct de_glb *)(de_mux_base +
 				  SUNXI_DE2_MUX_GLB_REGS);
@@ -87,17 +58,6 @@ static void sunxi_de2_mode_set(ulong de_mux_base, int mux,
 	int channel;
 	u32 format;
 
-	/* enable clock */
-#ifdef CONFIG_MACH_SUN8I_H3
-	setbits_le32(&de_clk_regs->rst_cfg, (mux == 0) ? 1 : 4);
-#else
-	setbits_le32(&de_clk_regs->rst_cfg, BIT(mux));
-#endif
-	setbits_le32(&de_clk_regs->gate_cfg, BIT(mux));
-	setbits_le32(&de_clk_regs->bus_cfg, BIT(mux));
-
-	clrbits_le32(&de_clk_regs->sel_cfg, 1);
-
 	writel(SUNXI_DE2_MUX_GLB_CTL_EN, &de_glb_regs->ctl);
 	writel(0, &de_glb_regs->status);
 	writel(1, &de_glb_regs->dbuff);
@@ -189,6 +149,8 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase,
 	struct video_priv *uc_priv = dev_get_uclass_priv(dev);
 	struct display_timing timing;
 	struct display_plat *disp_uc_plat;
+	struct reset_ctl_bulk resets;
+	struct clk_bulk clocks;
 	int ret;
 
 	disp_uc_plat = dev_get_uclass_plat(disp);
@@ -206,8 +168,23 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase,
 		return ret;
 	}
 
-	sunxi_de2_composer_init();
-	sunxi_de2_mode_set((ulong)dev_read_addr(dev), mux, &timing,
+	ret = reset_get_bulk(dev, &resets);
+	if (ret)
+		return ret;
+
+	ret = clk_get_bulk(dev, &clocks);
+	if (ret)
+		return ret;
+
+	ret = clk_enable_bulk(&clocks);
+	if (ret)
+		return ret;
+
+	ret = reset_deassert_bulk(&resets);
+	if (ret)
+		return ret;
+
+	sunxi_de2_mode_set((ulong)dev_read_addr(dev), &timing,
 			   1 << l2bpp, fbbase, is_composite);
 
 	ret = display_enable(disp, 1 << l2bpp, &timing);
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 17/19] video: dw-hdmi: modify phy init callback to include full timings
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
                   ` (15 preceding siblings ...)
  2021-03-06 19:54 ` [PATCH v2 16/19] video: sunxi: de2: switch clock setup to DM model Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-03-06 19:54 ` [PATCH v2 18/19] video: sunxi: Add DW HDMI PHY driver Jernej Skrabec
  2021-03-06 19:54 ` [PATCH v2 19/19] video: sunxi: dw-hdmi: Use new " Jernej Skrabec
  18 siblings, 0 replies; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

Currently PHY init callback has only pixel clock as a parameter, but
other timing parameters may be needed for custom PHYs. Modify callback
signature to include full timings.

Cc: Neil Armstrong <narmstrong@baylibre.com>
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 drivers/video/dw_hdmi.c             | 6 +++---
 drivers/video/meson/meson_dw_hdmi.c | 5 +++--
 drivers/video/sunxi/sunxi_dw_hdmi.c | 7 ++++---
 include/dw_hdmi.h                   | 4 ++--
 4 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/video/dw_hdmi.c b/drivers/video/dw_hdmi.c
index c4fbb1829446..8d71f713f99f 100644
--- a/drivers/video/dw_hdmi.c
+++ b/drivers/video/dw_hdmi.c
@@ -901,7 +901,7 @@ static const u8 pre_buf[] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9,
 };
 
-int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock)
+int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, const struct display_timing *edid)
 {
 	int i, ret;
 
@@ -912,7 +912,7 @@ int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock)
 		hdmi_phy_enable_tmds(hdmi, 0);
 		hdmi_phy_enable_power(hdmi, 0);
 
-		ret = hdmi_phy_configure(hdmi, mpixelclock);
+		ret = hdmi_phy_configure(hdmi, edid->pixelclock.typ);
 		if (ret) {
 			debug("hdmi phy config failure %d\n", ret);
 			return ret;
@@ -988,7 +988,7 @@ int dw_hdmi_enable(struct dw_hdmi *hdmi, const struct display_timing *edid)
 
 	hdmi_av_composer(hdmi, edid);
 
-	ret = hdmi->phy_set(hdmi, edid->pixelclock.typ);
+	ret = hdmi->phy_set(hdmi, edid);
 	if (ret)
 		return ret;
 
diff --git a/drivers/video/meson/meson_dw_hdmi.c b/drivers/video/meson/meson_dw_hdmi.c
index e5f281320534..7558814b3491 100644
--- a/drivers/video/meson/meson_dw_hdmi.c
+++ b/drivers/video/meson/meson_dw_hdmi.c
@@ -292,7 +292,8 @@ static void meson_dw_hdmi_phy_setup_mode(struct meson_dw_hdmi *priv,
 	}
 }
 
-static int meson_dw_hdmi_phy_init(struct dw_hdmi *hdmi, uint pixel_clock)
+static int meson_dw_hdmi_phy_init(struct dw_hdmi *hdmi,
+				  const struct display_timing *edid)
 {
 	struct meson_dw_hdmi *priv = container_of(hdmi, struct meson_dw_hdmi,
 						  hdmi);
@@ -322,7 +323,7 @@ static int meson_dw_hdmi_phy_init(struct dw_hdmi *hdmi, uint pixel_clock)
 	dw_hdmi_top_write(hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2);
 
 	/* Setup PHY parameters */
-	meson_dw_hdmi_phy_setup_mode(priv, pixel_clock);
+	meson_dw_hdmi_phy_setup_mode(priv, edid->pixelclock.typ);
 
 	/* Setup PHY */
 	dw_hdmi_hhi_update_bits(priv, HHI_HDMI_PHY_CNTL1,
diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c
index 0744954fa15f..483d57293155 100644
--- a/drivers/video/sunxi/sunxi_dw_hdmi.c
+++ b/drivers/video/sunxi/sunxi_dw_hdmi.c
@@ -266,12 +266,13 @@ static void sunxi_dw_hdmi_lcdc_init(int mux, const struct display_timing *edid,
 	lcdc_enable(lcdc, bpp);
 }
 
-static int sunxi_dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock)
+static int sunxi_dw_hdmi_phy_cfg(struct dw_hdmi *hdmi,
+				 const struct display_timing *edid)
 {
 	int phy_div;
 
-	sunxi_dw_hdmi_pll_set(mpixelclock / 1000, &phy_div);
-	sunxi_dw_hdmi_phy_set(hdmi, mpixelclock, phy_div);
+	sunxi_dw_hdmi_pll_set(edid->pixelclock.typ / 1000, &phy_div);
+	sunxi_dw_hdmi_phy_set(hdmi, edid->pixelclock.typ, phy_div);
 
 	return 0;
 }
diff --git a/include/dw_hdmi.h b/include/dw_hdmi.h
index 8acae3839fb3..46b87916b8bb 100644
--- a/include/dw_hdmi.h
+++ b/include/dw_hdmi.h
@@ -544,12 +544,12 @@ struct dw_hdmi {
 	struct hdmi_data_info hdmi_data;
 	struct udevice *ddc_bus;
 
-	int (*phy_set)(struct dw_hdmi *hdmi, uint mpixelclock);
+	int (*phy_set)(struct dw_hdmi *hdmi, const struct display_timing *edid);
 	void (*write_reg)(struct dw_hdmi *hdmi, u8 val, int offset);
 	u8 (*read_reg)(struct dw_hdmi *hdmi, int offset);
 };
 
-int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock);
+int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, const struct display_timing *edid);
 int dw_hdmi_phy_wait_for_hpd(struct dw_hdmi *hdmi);
 void dw_hdmi_phy_init(struct dw_hdmi *hdmi);
 
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 18/19] video: sunxi: Add DW HDMI PHY driver
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
                   ` (16 preceding siblings ...)
  2021-03-06 19:54 ` [PATCH v2 17/19] video: dw-hdmi: modify phy init callback to include full timings Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  2021-03-08  7:57   ` Jagan Teki
  2021-03-06 19:54 ` [PATCH v2 19/19] video: sunxi: dw-hdmi: Use new " Jernej Skrabec
  18 siblings, 1 reply; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

This commit adds standalone driver for DW HDMI PHY. It deprecates code
which is included in sunxi dw-hdmi platform driver.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 arch/arm/mach-sunxi/Kconfig             |   1 +
 drivers/video/sunxi/Makefile            |   2 +-
 drivers/video/sunxi/sunxi_dw_hdmi_phy.c | 423 ++++++++++++++++++++++++
 drivers/video/sunxi/sunxi_dw_hdmi_phy.h |  24 ++
 4 files changed, 449 insertions(+), 1 deletion(-)
 create mode 100644 drivers/video/sunxi/sunxi_dw_hdmi_phy.c
 create mode 100644 drivers/video/sunxi/sunxi_dw_hdmi_phy.h

diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 34ef1f4b030f..5f2df7727357 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -973,6 +973,7 @@ config VIDEO_DE2
 	select CLK_SUN8I_DE2
 	select DM_VIDEO
 	select DISPLAY
+	select PHY
 	select VIDEO_DW_HDMI
 	imply VIDEO_DT_SIMPLEFB
 	default y
diff --git a/drivers/video/sunxi/Makefile b/drivers/video/sunxi/Makefile
index 4321673312bf..22ec17fb4fd2 100644
--- a/drivers/video/sunxi/Makefile
+++ b/drivers/video/sunxi/Makefile
@@ -4,4 +4,4 @@
 # Wolfgang Denk, DENX Software Engineering, wd at denx.de.
 
 obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o simplefb_common.o lcdc.o tve_common.o ../videomodes.o
-obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o simplefb_common.o lcdc.o sunxi_lcd.o
+obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o sunxi_dw_hdmi_phy.o simplefb_common.o lcdc.o sunxi_lcd.o
diff --git a/drivers/video/sunxi/sunxi_dw_hdmi_phy.c b/drivers/video/sunxi/sunxi_dw_hdmi_phy.c
new file mode 100644
index 000000000000..bed5c2fdfe81
--- /dev/null
+++ b/drivers/video/sunxi/sunxi_dw_hdmi_phy.c
@@ -0,0 +1,423 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Allwinner DW HDMI PHY driver
+ *
+ * (C) Copyright 2021 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <reset.h>
+#include <time.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include "sunxi_dw_hdmi_phy.h"
+
+#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_REXT_EN	BIT(31)
+
+#define SUN8I_HDMI_PHY_READ_EN_MAGIC		0x54524545
+
+#define SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC		0x42494E47
+
+#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_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_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_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_MSK	BIT(26)
+#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT	26
+#define SUN8I_HDMI_PHY_PLL_CFG1_PLLEN		BIT(25)
+#define SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(x)	((x) << 22)
+#define SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(x)	((x) << 20)
+#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_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_SOUT_DIV2	BIT(0)
+
+#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)
+
+struct sunxi_hdmi_phy {
+	u32 dbg_ctrl;
+	u32 rext_ctrl;
+	u32 res1[2];
+	u32 read_en;
+	u32 unscramble;
+	u32 res2[2];
+	u32 ana_cfg1;
+	u32 ana_cfg2;
+	u32 ana_cfg3;
+	u32 pll_cfg1;
+	u32 pll_cfg2;
+	u32 pll_cfg3;
+	u32 ana_sts;
+};
+
+struct sunxi_dw_hdmi_phy_priv {
+	void *base;
+	struct clk clk_bus;
+	struct clk clk_mod;
+	uint rcal;
+	struct reset_ctl reset;
+};
+
+void sunxi_dw_hdmi_phy_set(struct phy *_phy, const struct display_timing *edid,
+			   int clk_div)
+{
+	struct sunxi_dw_hdmi_phy_priv *priv = dev_get_priv(_phy->dev);
+	struct sunxi_hdmi_phy *phy = priv->base;
+	u32 pll_cfg1, pll_cfg2, ana_cfg1, ana_cfg2, ana_cfg3;
+	u32 tmp, b_offset = 0;
+
+	/* bandwidth / frequency independent settings */
+
+	pll_cfg1 = 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 = SUN8I_HDMI_PHY_PLL_CFG2_SV_H |
+		   SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN_EN |
+		   SUN8I_HDMI_PHY_PLL_CFG2_SDIV2;
+
+	ana_cfg1 = 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_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 = 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 = 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 (edid->pixelclock.typ <= 27000000) {
+		pll_cfg1 |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
+			    SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
+		pll_cfg2 |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
+			    SUN8I_HDMI_PHY_PLL_CFG2_S(4);
+		ana_cfg1 |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW;
+		ana_cfg2 |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) |
+			    SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(priv->rcal);
+		ana_cfg3 |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(3) |
+			    SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(5);
+	} else if (edid->pixelclock.typ <= 74250000) {
+		pll_cfg1 |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
+			    SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
+		pll_cfg2 |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
+			    SUN8I_HDMI_PHY_PLL_CFG2_S(5);
+		ana_cfg1 |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW;
+		ana_cfg2 |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) |
+			    SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(priv->rcal);
+		ana_cfg3 |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(5) |
+			    SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(7);
+	} else if (edid->pixelclock.typ <= 148500000) {
+		pll_cfg1 |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
+			    SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
+		pll_cfg2 |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
+			    SUN8I_HDMI_PHY_PLL_CFG2_S(6);
+		ana_cfg2 |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK |
+			    SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW |
+			    SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(2);
+		ana_cfg3 |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(7) |
+			    SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(9);
+	} else {
+		b_offset = 2;
+		pll_cfg1 |= SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63);
+		pll_cfg2 |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(6) |
+			    SUN8I_HDMI_PHY_PLL_CFG2_S(7);
+		ana_cfg2 |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK |
+			    SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW |
+			    SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4);
+		ana_cfg3 |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(9) |
+			    SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(13) |
+			    SUN8I_HDMI_PHY_ANA_CFG3_REG_EMP(3);
+	}
+
+	writel(pll_cfg1, &phy->pll_cfg1);
+	writel(pll_cfg2 | (clk_div - 1), &phy->pll_cfg2);
+	mdelay(10);
+	writel(SUN8I_HDMI_PHY_PLL_CFG3_SOUT_DIV2, &phy->pll_cfg3);
+	setbits_le32(&phy->pll_cfg1, SUN8I_HDMI_PHY_PLL_CFG1_PLLEN);
+	mdelay(100);
+	tmp = readl(&phy->ana_sts) & SUN8I_HDMI_PHY_ANA_STS_B_OUT_MSK;
+	tmp >>= SUN8I_HDMI_PHY_ANA_STS_B_OUT_SHIFT;
+	tmp = min(tmp + b_offset, (u32)0x3f);
+	setbits_le32(&phy->pll_cfg1,
+		     SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 |
+		     SUN8I_HDMI_PHY_PLL_CFG1_REG_OD);
+	setbits_le32(&phy->pll_cfg1, tmp);
+	mdelay(100);
+	writel(ana_cfg1, &phy->ana_cfg1);
+	writel(ana_cfg2, &phy->ana_cfg2);
+	writel(ana_cfg3, &phy->ana_cfg3);
+
+	if (edid->flags & DISPLAY_FLAGS_VSYNC_LOW)
+		setbits_le32(&phy->dbg_ctrl,
+			     SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC);
+
+	if (edid->flags & DISPLAY_FLAGS_HSYNC_LOW)
+		setbits_le32(&phy->dbg_ctrl,
+			     SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC);
+
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL);
+}
+
+static int sunxi_dw_hdmi_phy_init(struct phy *phy)
+{
+	struct sunxi_dw_hdmi_phy_priv *priv = dev_get_priv(phy->dev);
+	int ret;
+
+	ret = reset_deassert(&priv->reset);
+	if (ret)
+		return ret;
+
+	ret = clk_enable(&priv->clk_bus);
+	if (ret)
+		return ret;
+
+	ret = clk_enable(&priv->clk_mod);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int sunxi_dw_hdmi_phy_power_on(struct phy *_phy)
+{
+	struct sunxi_dw_hdmi_phy_priv *priv = dev_get_priv(_phy->dev);
+	struct sunxi_hdmi_phy *phy = priv->base;
+	unsigned long tmo;
+
+	/* enable read access to HDMI controller */
+	writel(SUN8I_HDMI_PHY_READ_EN_MAGIC, &phy->read_en);
+	/* descramble register offsets */
+	writel(SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC, &phy->unscramble);
+
+	writel(0, &phy->ana_cfg1);
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_ENBI);
+	udelay(5);
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN);
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_ENVBS);
+	udelay(10);
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_LDOEN);
+	udelay(5);
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_CKEN);
+	udelay(40);
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL);
+	udelay(100);
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG);
+	setbits_le32(&phy->ana_cfg1,
+		     SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
+		     SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
+		     SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2);
+
+	/* Note that Allwinner code doesn't fail in case of timeout */
+	tmo = timer_get_us() + 2000;
+	while ((readl(&phy->ana_sts) & SUN8I_HDMI_PHY_ANA_STS_RCALEND2D) == 0) {
+		if (timer_get_us() > tmo) {
+			printf("Warning: HDMI PHY init timeout!\n");
+			break;
+		}
+	}
+
+	setbits_le32(&phy->ana_cfg1,
+		     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);
+	setbits_le32(&phy->ana_cfg1, SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK);
+
+	/* enable DDC communication */
+	writel(SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
+	       SUN8I_HDMI_PHY_ANA_CFG3_SDAEN, &phy->ana_cfg3);
+
+	priv->rcal = readl(&phy->ana_sts) & SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK;
+	priv->rcal >>= 2;
+
+	return 0;
+}
+
+/*
+ * This callback is abused for executing code after last register in
+ * controller is set.
+ */
+static int sunxi_dw_hdmi_phy_exit(struct phy *_phy)
+{
+	struct sunxi_dw_hdmi_phy_priv *priv = dev_get_priv(_phy->dev);
+	struct sunxi_hdmi_phy *phy = priv->base;
+
+	writel(0, &phy->unscramble);
+
+	return 0;
+}
+
+static struct phy_ops sunxi_dw_hdmi_phy_ops = {
+	.init = sunxi_dw_hdmi_phy_init,
+	.power_on = sunxi_dw_hdmi_phy_power_on,
+	.exit = sunxi_dw_hdmi_phy_exit,
+};
+
+static int sunxi_dw_hdmi_phy_probe(struct udevice *dev)
+{
+	struct sunxi_dw_hdmi_phy_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	priv->base = dev_read_addr_ptr(dev);
+	if (!priv->base)
+		return -EINVAL;
+
+	ret = reset_get_by_index(dev, 0, &priv->reset);
+	if (ret)
+		return ret;
+
+	ret = clk_get_by_name(dev, "bus", &priv->clk_bus);
+	if (ret)
+		return ret;
+
+	ret = clk_get_by_name(dev, "mod", &priv->clk_mod);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct udevice_id sunxi_dw_hdmi_phy_ids[] = {
+	{ .compatible = "allwinner,sun8i-h3-hdmi-phy" },
+	{ .compatible = "allwinner,sun50i-a64-hdmi-phy" },
+	{ }
+};
+
+U_BOOT_DRIVER(sunxi_dw_hdmi_phy) = {
+	.name		= "sunxi_dw_hdmi_phy",
+	.id		= UCLASS_PHY,
+	.of_match	= sunxi_dw_hdmi_phy_ids,
+	.ops		= &sunxi_dw_hdmi_phy_ops,
+	.probe		= sunxi_dw_hdmi_phy_probe,
+	.priv_auto	= sizeof(struct sunxi_dw_hdmi_phy_priv),
+};
diff --git a/drivers/video/sunxi/sunxi_dw_hdmi_phy.h b/drivers/video/sunxi/sunxi_dw_hdmi_phy.h
new file mode 100644
index 000000000000..78f85a413aaf
--- /dev/null
+++ b/drivers/video/sunxi/sunxi_dw_hdmi_phy.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2021 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#ifndef __SUNXI_DW_HDMI_PHY_H
+#define __SUNXI_DW_HDMI_PHY_H
+
+#include <edid.h>
+
+/**
+ * sunxi_dw_hdmi_phy_set() - configure sunxi DW HDMI PHY
+ *
+ * Configure Sunxi DW HDMI PHY as found in A64, H3, H5 and other SoCs according
+ * to speficied mode.
+ *
+ * @phy: PHY port
+ * @edid: timing to configure
+ * @clk_div: Clock divider to set
+ */
+void sunxi_dw_hdmi_phy_set(struct phy *phy, const struct display_timing *edid,
+			   int clk_div);
+
+#endif
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 19/19] video: sunxi: dw-hdmi: Use new PHY driver
  2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
                   ` (17 preceding siblings ...)
  2021-03-06 19:54 ` [PATCH v2 18/19] video: sunxi: Add DW HDMI PHY driver Jernej Skrabec
@ 2021-03-06 19:54 ` Jernej Skrabec
  18 siblings, 0 replies; 37+ messages in thread
From: Jernej Skrabec @ 2021-03-06 19:54 UTC (permalink / raw)
  To: u-boot

Remove direct PHY managing from dw-hdmi platform driver and use
dedicated driver instead. While at it, enable clocks and deassert reset
lines through clk and reset framework instead of manually configuring
bits.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 drivers/video/sunxi/sunxi_dw_hdmi.c | 225 +++++-----------------------
 1 file changed, 36 insertions(+), 189 deletions(-)

diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c
index 483d57293155..16051baca8c5 100644
--- a/drivers/video/sunxi/sunxi_dw_hdmi.c
+++ b/drivers/video/sunxi/sunxi_dw_hdmi.c
@@ -5,190 +5,26 @@
  * (C) Copyright 2017 Jernej Skrabec <jernej.skrabec@siol.net>
  */
 
+#include <clk.h>
 #include <common.h>
 #include <display.h>
 #include <dm.h>
 #include <dw_hdmi.h>
 #include <edid.h>
-#include <log.h>
-#include <time.h>
+#include <generic-phy.h>
+#include <reset.h>
 #include <asm/io.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/lcdc.h>
 #include <linux/bitops.h>
-#include <linux/delay.h>
+#include "sunxi_dw_hdmi_phy.h"
 
 struct sunxi_dw_hdmi_priv {
 	struct dw_hdmi hdmi;
 	int mux;
+	struct phy phy;
 };
 
-struct sunxi_hdmi_phy {
-	u32 pol;
-	u32 res1[3];
-	u32 read_en;
-	u32 unscramble;
-	u32 res2[2];
-	u32 ctrl;
-	u32 unk1;
-	u32 unk2;
-	u32 pll;
-	u32 clk;
-	u32 unk3;
-	u32 status;
-};
-
-#define HDMI_PHY_OFFS 0x10000
-
-static int sunxi_dw_hdmi_get_divider(uint clock)
-{
-	/*
-	 * Due to missing documentaion of HDMI PHY, we know correct
-	 * settings only for following four PHY dividers. Select one
-	 * based on clock speed.
-	 */
-	if (clock <= 27000000)
-		return 11;
-	else if (clock <= 74250000)
-		return 4;
-	else if (clock <= 148500000)
-		return 2;
-	else
-		return 1;
-}
-
-static void sunxi_dw_hdmi_phy_init(struct dw_hdmi *hdmi)
-{
-	struct sunxi_hdmi_phy * const phy =
-		(struct sunxi_hdmi_phy *)(hdmi->ioaddr + HDMI_PHY_OFFS);
-	unsigned long tmo;
-	u32 tmp;
-
-	/*
-	 * HDMI PHY settings are taken as-is from Allwinner BSP code.
-	 * There is no documentation.
-	 */
-	writel(0, &phy->ctrl);
-	setbits_le32(&phy->ctrl, BIT(0));
-	udelay(5);
-	setbits_le32(&phy->ctrl, BIT(16));
-	setbits_le32(&phy->ctrl, BIT(1));
-	udelay(10);
-	setbits_le32(&phy->ctrl, BIT(2));
-	udelay(5);
-	setbits_le32(&phy->ctrl, BIT(3));
-	udelay(40);
-	setbits_le32(&phy->ctrl, BIT(19));
-	udelay(100);
-	setbits_le32(&phy->ctrl, BIT(18));
-	setbits_le32(&phy->ctrl, 7 << 4);
-
-	/* Note that Allwinner code doesn't fail in case of timeout */
-	tmo = timer_get_us() + 2000;
-	while ((readl(&phy->status) & 0x80) == 0) {
-		if (timer_get_us() > tmo) {
-			printf("Warning: HDMI PHY init timeout!\n");
-			break;
-		}
-	}
-
-	setbits_le32(&phy->ctrl, 0xf << 8);
-	setbits_le32(&phy->ctrl, BIT(7));
-
-	writel(0x39dc5040, &phy->pll);
-	writel(0x80084343, &phy->clk);
-	udelay(10000);
-	writel(1, &phy->unk3);
-	setbits_le32(&phy->pll, BIT(25));
-	udelay(100000);
-	tmp = (readl(&phy->status) & 0x1f800) >> 11;
-	setbits_le32(&phy->pll, BIT(31) | BIT(30));
-	setbits_le32(&phy->pll, tmp);
-	writel(0x01FF0F7F, &phy->ctrl);
-	writel(0x80639000, &phy->unk1);
-	writel(0x0F81C405, &phy->unk2);
-
-	/* enable read access to HDMI controller */
-	writel(0x54524545, &phy->read_en);
-	/* descramble register offsets */
-	writel(0x42494E47, &phy->unscramble);
-}
-
-static void sunxi_dw_hdmi_phy_set(struct dw_hdmi *hdmi, uint clock, int phy_div)
-{
-	struct sunxi_hdmi_phy * const phy =
-		(struct sunxi_hdmi_phy *)(hdmi->ioaddr + HDMI_PHY_OFFS);
-	int div = sunxi_dw_hdmi_get_divider(clock);
-	u32 tmp;
-
-	/*
-	 * Unfortunately, we don't know much about those magic
-	 * numbers. They are taken from Allwinner BSP driver.
-	 */
-	switch (div) {
-	case 1:
-		writel(0x30dc5fc0, &phy->pll);
-		writel(0x800863C0 | (phy_div - 1), &phy->clk);
-		mdelay(10);
-		writel(0x00000001, &phy->unk3);
-		setbits_le32(&phy->pll, BIT(25));
-		mdelay(200);
-		tmp = (readl(&phy->status) & 0x1f800) >> 11;
-		setbits_le32(&phy->pll, BIT(31) | BIT(30));
-		if (tmp < 0x3d)
-			setbits_le32(&phy->pll, tmp + 2);
-		else
-			setbits_le32(&phy->pll, 0x3f);
-		mdelay(100);
-		writel(0x01FFFF7F, &phy->ctrl);
-		writel(0x8063b000, &phy->unk1);
-		writel(0x0F8246B5, &phy->unk2);
-		break;
-	case 2:
-		writel(0x39dc5040, &phy->pll);
-		writel(0x80084380 | (phy_div - 1), &phy->clk);
-		mdelay(10);
-		writel(0x00000001, &phy->unk3);
-		setbits_le32(&phy->pll, BIT(25));
-		mdelay(100);
-		tmp = (readl(&phy->status) & 0x1f800) >> 11;
-		setbits_le32(&phy->pll, BIT(31) | BIT(30));
-		setbits_le32(&phy->pll, tmp);
-		writel(0x01FFFF7F, &phy->ctrl);
-		writel(0x8063a800, &phy->unk1);
-		writel(0x0F81C485, &phy->unk2);
-		break;
-	case 4:
-		writel(0x39dc5040, &phy->pll);
-		writel(0x80084340 | (phy_div - 1), &phy->clk);
-		mdelay(10);
-		writel(0x00000001, &phy->unk3);
-		setbits_le32(&phy->pll, BIT(25));
-		mdelay(100);
-		tmp = (readl(&phy->status) & 0x1f800) >> 11;
-		setbits_le32(&phy->pll, BIT(31) | BIT(30));
-		setbits_le32(&phy->pll, tmp);
-		writel(0x01FFFF7F, &phy->ctrl);
-		writel(0x8063b000, &phy->unk1);
-		writel(0x0F81C405, &phy->unk2);
-		break;
-	case 11:
-		writel(0x39dc5040, &phy->pll);
-		writel(0x80084300 | (phy_div - 1), &phy->clk);
-		mdelay(10);
-		writel(0x00000001, &phy->unk3);
-		setbits_le32(&phy->pll, BIT(25));
-		mdelay(100);
-		tmp = (readl(&phy->status) & 0x1f800) >> 11;
-		setbits_le32(&phy->pll, BIT(31) | BIT(30));
-		setbits_le32(&phy->pll, tmp);
-		writel(0x01FFFF7F, &phy->ctrl);
-		writel(0x8063b000, &phy->unk1);
-		writel(0x0F81C405, &phy->unk2);
-		break;
-	}
-}
-
 static void sunxi_dw_hdmi_pll_set(uint clk_khz, int *phy_div)
 {
 	int value, n, m, div, diff;
@@ -269,10 +105,12 @@ static void sunxi_dw_hdmi_lcdc_init(int mux, const struct display_timing *edid,
 static int sunxi_dw_hdmi_phy_cfg(struct dw_hdmi *hdmi,
 				 const struct display_timing *edid)
 {
+	struct sunxi_dw_hdmi_priv *priv =
+		container_of(hdmi, struct sunxi_dw_hdmi_priv, hdmi);
 	int phy_div;
 
 	sunxi_dw_hdmi_pll_set(edid->pixelclock.typ / 1000, &phy_div);
-	sunxi_dw_hdmi_phy_set(hdmi, edid->pixelclock.typ, phy_div);
+	sunxi_dw_hdmi_phy_set(&priv->phy, edid, phy_div);
 
 	return 0;
 }
@@ -294,8 +132,6 @@ static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp,
 				const struct display_timing *edid)
 {
 	struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev);
-	struct sunxi_hdmi_phy * const phy =
-		(struct sunxi_hdmi_phy *)(priv->hdmi.ioaddr + HDMI_PHY_OFFS);
 	int ret;
 
 	ret = dw_hdmi_enable(&priv->hdmi, edid);
@@ -304,21 +140,13 @@ static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp,
 
 	sunxi_dw_hdmi_lcdc_init(priv->mux, edid, panel_bpp);
 
-	if (edid->flags & DISPLAY_FLAGS_VSYNC_LOW)
-		setbits_le32(&phy->pol, 0x200);
-
-	if (edid->flags & DISPLAY_FLAGS_HSYNC_LOW)
-		setbits_le32(&phy->pol, 0x100);
-
-	setbits_le32(&phy->ctrl, 0xf << 12);
-
 	/*
 	 * This is last hdmi access before boot, so scramble addresses
 	 * again or othwerwise BSP driver won't work. Dummy read is
 	 * needed or otherwise last write doesn't get written correctly.
 	 */
 	(void)readb(priv->hdmi.ioaddr);
-	writel(0, &phy->unscramble);
+	generic_phy_exit(&priv->phy);
 
 	return 0;
 }
@@ -343,8 +171,14 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev)
 	struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev);
 	struct sunxi_ccm_reg * const ccm =
 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+	struct reset_ctl_bulk resets;
+	struct clk_bulk clocks;
 	int ret;
 
+	ret = generic_phy_get_by_name(dev, "phy", &priv->phy);
+	if (ret)
+		return ret;
+
 	/* Set pll3 to 297 MHz */
 	clock_set_pll3(297000000);
 
@@ -352,19 +186,32 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev)
 	clrsetbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_PLL_MASK,
 			CCM_HDMI_CTRL_PLL3);
 
-	/* Set ahb gating to pass */
-	setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI);
-	setbits_le32(&ccm->ahb_reset1_cfg, 1 << AHB_RESET_OFFSET_HDMI2);
-	setbits_le32(&ccm->ahb_gate1, 1 << AHB_GATE_OFFSET_HDMI);
-	setbits_le32(&ccm->hdmi_slow_clk_cfg, CCM_HDMI_SLOW_CTRL_DDC_GATE);
+	ret = generic_phy_init(&priv->phy);
+	if (ret)
+		return ret;
 
-	/* Clock on */
-	setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
+	ret = reset_get_bulk(dev, &resets);
+	if (ret)
+		return ret;
 
-	sunxi_dw_hdmi_phy_init(&priv->hdmi);
+	ret = clk_get_bulk(dev, &clocks);
+	if (ret)
+		return ret;
+
+	ret = clk_enable_bulk(&clocks);
+	if (ret)
+		return ret;
+
+	ret = reset_deassert_bulk(&resets);
+	if (ret)
+		return ret;
 
 	priv->mux = uc_plat->source_id;
 
+	ret = generic_phy_power_on(&priv->phy);
+	if (ret)
+		return ret;
+
 	ret = dw_hdmi_phy_wait_for_hpd(&priv->hdmi);
 	if (ret < 0) {
 		debug("hdmi can not get hpd signal\n");
-- 
2.30.1

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH v2 04/19] common: edid: extract code for detailed timing search
  2021-03-06 19:54 ` [PATCH v2 04/19] common: edid: extract code for detailed timing search Jernej Skrabec
@ 2021-03-07  1:29   ` Andre Przywara
  0 siblings, 0 replies; 37+ messages in thread
From: Andre Przywara @ 2021-03-07  1:29 UTC (permalink / raw)
  To: u-boot

On Sat,  6 Mar 2021 20:54:22 +0100
Jernej Skrabec <jernej.skrabec@siol.net> wrote:

> Code which searches for valid detailed timing entry will be used in more
> places. Extract it.
> 
> No functional change is made. However, descriptors are casted to
> edid_detailed_timing instead of edid_monitor_descriptor. Descriptor can
> be of either type, but since we're interested only in DTD, it is more
> fitting to cast to edid_detailed_timing.

Thanks for adding the explanation!
> 
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

> ---
>  common/edid.c | 49 ++++++++++++++++++++++++++++---------------------
>  1 file changed, 28 insertions(+), 21 deletions(-)
> 
> diff --git a/common/edid.c b/common/edid.c
> index 1cb7177742e8..a6c875d9c8e8 100644
> --- a/common/edid.c
> +++ b/common/edid.c
> @@ -169,6 +169,29 @@ static bool cea_is_hdmi_vsdb_present(struct edid_cea861_info *info)
>  	return false;
>  }
>  
> +static bool edid_find_valid_timing(void *buf, int count,
> +				   struct display_timing *timing,
> +				   bool (*mode_valid)(void *priv,
> +					const struct display_timing *timing),
> +				   void *mode_valid_priv)
> +{
> +	struct edid_detailed_timing *t = buf;
> +	bool found = false;
> +	int i;
> +
> +	for (i = 0; i < count && !found; i++, t++)
> +		if (EDID_DETAILED_TIMING_PIXEL_CLOCK(*t) != 0) {
> +			decode_timing((u8 *)t, timing);
> +			if (mode_valid)
> +				found = mode_valid(mode_valid_priv,
> +						   timing);
> +			else
> +				found = true;
> +		}
> +
> +	return found;
> +}
> +
>  int edid_get_timing_validate(u8 *buf, int buf_size,
>  			     struct display_timing *timing,
>  			     int *panel_bits_per_colourp,
> @@ -177,8 +200,7 @@ int edid_get_timing_validate(u8 *buf, int buf_size,
>  			     void *mode_valid_priv)
>  {
>  	struct edid1_info *edid = (struct edid1_info *)buf;
> -	bool timing_done;
> -	int i;
> +	bool found;
>  
>  	if (buf_size < sizeof(*edid) || edid_check_info(edid)) {
>  		debug("%s: Invalid buffer\n", __func__);
> @@ -195,25 +217,10 @@ int edid_get_timing_validate(u8 *buf, int buf_size,
>  		return -ENOENT;
>  	}
>  
> -	/* Look for detailed timing */
> -	timing_done = false;
> -	for (i = 0; i < 4; i++) {
> -		struct edid_monitor_descriptor *desc;
> -
> -		desc = &edid->monitor_details.descriptor[i];
> -		if (desc->zero_flag_1 != 0) {
> -			decode_timing((u8 *)desc, timing);
> -			if (mode_valid)
> -				timing_done = mode_valid(mode_valid_priv,
> -							 timing);
> -			else
> -				timing_done = true;
> -
> -			if (timing_done)
> -				break;
> -		}
> -	}
> -	if (!timing_done)
> +	/* Look for detailed timing in base EDID */
> +	found = edid_find_valid_timing(edid->monitor_details.descriptor, 4,
> +				       timing, mode_valid, mode_valid_priv);
> +	if (!found)
>  		return -EINVAL;
>  
>  	if (edid->version != 1 || edid->revision < 4) {

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 06/19] video: sunxi: Use DW-HDMI hpd function
  2021-03-06 19:54 ` [PATCH v2 06/19] video: sunxi: Use DW-HDMI hpd function Jernej Skrabec
@ 2021-03-07  1:30   ` Andre Przywara
  0 siblings, 0 replies; 37+ messages in thread
From: Andre Przywara @ 2021-03-07  1:30 UTC (permalink / raw)
  To: u-boot

On Sat,  6 Mar 2021 20:54:24 +0100
Jernej Skrabec <jernej.skrabec@siol.net> wrote:

> It turns out that there are two ways how hot plug detection can be done.
> One is standard way for DW HDMI controller - checking bit 2 in 0x3004
> register. Another way is applicable only to Allwinner custom PHY - by
> checking bit 19 in register 0x10038. Both method are equally good as far
> as we know.
> 
> Use standard method in order to reduce amount of custom code.

Thanks for the clarification!
 
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

> ---
>  drivers/video/sunxi/sunxi_dw_hdmi.c | 34 +++++------------------------
>  1 file changed, 6 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c
> index e3811a2ec15f..37e78ff24111 100644
> --- a/drivers/video/sunxi/sunxi_dw_hdmi.c
> +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c
> @@ -114,28 +114,6 @@ static void sunxi_dw_hdmi_phy_init(void)
>  	writel(0x42494E47, &phy->unscramble);
>  }
>  
> -static int sunxi_dw_hdmi_get_plug_in_status(void)
> -{
> -	struct sunxi_hdmi_phy * const phy =
> -		(struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS);
> -
> -	return !!(readl(&phy->status) & (1 << 19));
> -}
> -
> -static int sunxi_dw_hdmi_wait_for_hpd(void)
> -{
> -	ulong start;
> -
> -	start = get_timer(0);
> -	do {
> -		if (sunxi_dw_hdmi_get_plug_in_status())
> -			return 0;
> -		udelay(100);
> -	} while (get_timer(start) < 300);
> -
> -	return -1;
> -}
> -
>  static void sunxi_dw_hdmi_phy_set(uint clock, int phy_div)
>  {
>  	struct sunxi_hdmi_phy * const phy =
> @@ -370,12 +348,6 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev)
>  
>  	sunxi_dw_hdmi_phy_init();
>  
> -	ret = sunxi_dw_hdmi_wait_for_hpd();
> -	if (ret < 0) {
> -		debug("hdmi can not get hpd signal\n");
> -		return -1;
> -	}
> -
>  	priv->hdmi.ioaddr = SUNXI_HDMI_BASE;
>  	priv->hdmi.i2c_clk_high = 0xd8;
>  	priv->hdmi.i2c_clk_low = 0xfe;
> @@ -383,6 +355,12 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev)
>  	priv->hdmi.phy_set = sunxi_dw_hdmi_phy_cfg;
>  	priv->mux = uc_plat->source_id;
>  
> +	ret = dw_hdmi_phy_wait_for_hpd(&priv->hdmi);
> +	if (ret < 0) {
> +		debug("hdmi can not get hpd signal\n");
> +		return -1;
> +	}
> +
>  	uclass_get_device_by_phandle(UCLASS_I2C, dev, "ddc-i2c-bus",
>  				     &priv->hdmi.ddc_bus);
>  

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 08/19] video: sunxi: Remove TV probe from DE2
  2021-03-06 19:54 ` [PATCH v2 08/19] video: sunxi: Remove TV probe from DE2 Jernej Skrabec
@ 2021-03-07  1:31   ` Andre Przywara
  0 siblings, 0 replies; 37+ messages in thread
From: Andre Przywara @ 2021-03-07  1:31 UTC (permalink / raw)
  To: u-boot

On Sat,  6 Mar 2021 20:54:26 +0100
Jernej Skrabec <jernej.skrabec@siol.net> wrote:

> TV driver was never fully implemented. Remove search for it from DE2
> driver.

Correct, there is no driver in the tree which would match this string.

> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Cheers,
Andre

> ---
>  drivers/video/sunxi/sunxi_de2.c | 15 +--------------
>  1 file changed, 1 insertion(+), 14 deletions(-)
> 
> diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c
> index a3e21aa5f13e..6b836a011944 100644
> --- a/drivers/video/sunxi/sunxi_de2.c
> +++ b/drivers/video/sunxi/sunxi_de2.c
> @@ -281,20 +281,7 @@ static int sunxi_de2_probe(struct udevice *dev)
>  
>  	debug("%s: hdmi display not found (ret=%d)\n", __func__, ret);
>  
> -	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
> -					"sunxi_tve", &disp);
> -	if (ret) {
> -		debug("%s: tv not found (ret=%d)\n", __func__, ret);
> -		return ret;
> -	}
> -
> -	ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, 1, true);
> -	if (ret)
> -		return ret;
> -
> -	video_set_flush_dcache(dev, 1);
> -
> -	return 0;
> +	return -ENODEV;
>  }
>  
>  static int sunxi_de2_bind(struct udevice *dev)

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 09/19] video: sunxi: de2: switch to public uclass functions
  2021-03-06 19:54 ` [PATCH v2 09/19] video: sunxi: de2: switch to public uclass functions Jernej Skrabec
@ 2021-03-07  1:32   ` Andre Przywara
  2021-03-07  7:35     ` Jernej Škrabec
  0 siblings, 1 reply; 37+ messages in thread
From: Andre Przywara @ 2021-03-07  1:32 UTC (permalink / raw)
  To: u-boot

On Sat,  6 Mar 2021 20:54:27 +0100
Jernej Skrabec <jernej.skrabec@siol.net> wrote:

> Currently DE2 driver uses functions which are defined in internal
> headers. They are not meant to be used outside of uclass framework.
> Switch DE2 driver to public ones. This has additional benefit that
> device_probe doesn't need to be called manually.

Indeed, good solution: for the calls in _probe(), we call de2_init()
right afterwards, which would explicitly call probe for the display, so
this both saves this call and the usage of the internal function.
For the calls in simplefb_setup: the DM framework checks if a device
has already been activated, so there is no problem with double probes.

However, actually testing this on a Pine64-LTS revealed that this breaks
on the A64: I only get a black screen (bisecting down to this commit).

I didn't investigate any further yet, just wanted to give a heads up.

Cheers,
Andre

> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> ---
>  drivers/video/sunxi/sunxi_de2.c | 29 ++++++++++-------------------
>  1 file changed, 10 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c
> index 6b836a011944..e02d359cd259 100644
> --- a/drivers/video/sunxi/sunxi_de2.c
> +++ b/drivers/video/sunxi/sunxi_de2.c
> @@ -19,8 +19,6 @@
>  #include <asm/io.h>
>  #include <asm/arch/clock.h>
>  #include <asm/arch/display2.h>
> -#include <dm/device-internal.h>
> -#include <dm/uclass-internal.h>
>  #include <linux/bitops.h>
>  #include "simplefb_common.h"
>  
> @@ -198,13 +196,6 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase,
>  
>  	disp_uc_plat->source_id = mux;
>  
> -	ret = device_probe(disp);
> -	if (ret) {
> -		debug("%s: device '%s' display won't probe (ret=%d)\n",
> -		      __func__, dev->name, ret);
> -		return ret;
> -	}
> -
>  	ret = display_read_timing(disp, &timing);
>  	if (ret) {
>  		debug("%s: Failed to read timings\n", __func__);
> @@ -245,8 +236,8 @@ static int sunxi_de2_probe(struct udevice *dev)
>  	if (!(gd->flags & GD_FLG_RELOC))
>  		return 0;
>  
> -	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
> -					 "sunxi_lcd", &disp);
> +	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> +					  DM_DRIVER_GET(sunxi_lcd), &disp);
>  	if (!ret) {
>  		int mux;
>  
> @@ -262,8 +253,8 @@ static int sunxi_de2_probe(struct udevice *dev)
>  
>  	debug("%s: lcd display not found (ret=%d)\n", __func__, ret);
>  
> -	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
> -					 "sunxi_dw_hdmi", &disp);
> +	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> +					  DM_DRIVER_GET(sunxi_dw_hdmi), &disp);
>  	if (!ret) {
>  		int mux;
>  		if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
> @@ -332,8 +323,8 @@ int sunxi_simplefb_setup(void *blob)
>  		mux = 1;
>  
>  	/* Skip simplefb setting if DE2 / HDMI is not present */
> -	ret = uclass_find_device_by_name(UCLASS_VIDEO,
> -					 "sunxi_de2", &de2);
> +	ret = uclass_get_device_by_driver(UCLASS_VIDEO,
> +					  DM_DRIVER_GET(sunxi_de2), &de2);
>  	if (ret) {
>  		debug("DE2 not present\n");
>  		return 0;
> @@ -342,8 +333,8 @@ int sunxi_simplefb_setup(void *blob)
>  		return 0;
>  	}
>  
> -	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
> -					 "sunxi_dw_hdmi", &hdmi);
> +	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> +					  DM_DRIVER_GET(sunxi_dw_hdmi), &hdmi);
>  	if (ret) {
>  		debug("HDMI not present\n");
>  	} else if (device_active(hdmi)) {
> @@ -355,8 +346,8 @@ int sunxi_simplefb_setup(void *blob)
>  		debug("HDMI present but not probed\n");
>  	}
>  
> -	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
> -					 "sunxi_lcd", &lcd);
> +	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> +					  DM_DRIVER_GET(sunxi_lcd), &lcd);
>  	if (ret)
>  		debug("LCD not present\n");
>  	else if (device_active(lcd))

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 10/19] video: sunxi: dw-hdmi: probe driver by compatible
  2021-03-06 19:54 ` [PATCH v2 10/19] video: sunxi: dw-hdmi: probe driver by compatible Jernej Skrabec
@ 2021-03-07  1:33   ` Andre Przywara
  0 siblings, 0 replies; 37+ messages in thread
From: Andre Przywara @ 2021-03-07  1:33 UTC (permalink / raw)
  To: u-boot

On Sat,  6 Mar 2021 20:54:28 +0100
Jernej Skrabec <jernej.skrabec@siol.net> wrote:

> Currently sunxi dw-hdmi driver is probed unconditionally, even if there
> is no such device.
> 
> Switch driver to probing via compatible string. This brings many
> benefits - driver can read DT node and allows driver to be always
> enabled.

Confirmed that this the one compatible string that all supported SoCs
use.

> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Thanks!
Andre

> ---
>  drivers/video/sunxi/sunxi_dw_hdmi.c | 10 ++++++----
>  1 file changed, 6 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c
> index 6d2bc206fc2c..6f77b2a43b40 100644
> --- a/drivers/video/sunxi/sunxi_dw_hdmi.c
> +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c
> @@ -372,14 +372,16 @@ static const struct dm_display_ops sunxi_dw_hdmi_ops = {
>  	.mode_valid = sunxi_dw_hdmi_mode_valid,
>  };
>  
> +static const struct udevice_id sunxi_dw_hdmi_ids[] = {
> +	{ .compatible = "allwinner,sun8i-a83t-dw-hdmi" },
> +	{ }
> +};
> +
>  U_BOOT_DRIVER(sunxi_dw_hdmi) = {
>  	.name	= "sunxi_dw_hdmi",
>  	.id	= UCLASS_DISPLAY,
> +	.of_match = sunxi_dw_hdmi_ids,
>  	.ops	= &sunxi_dw_hdmi_ops,
>  	.probe	= sunxi_dw_hdmi_probe,
>  	.priv_auto	= sizeof(struct sunxi_dw_hdmi_priv),
>  };
> -
> -U_BOOT_DRVINFO(sunxi_dw_hdmi) = {
> -	.name = "sunxi_dw_hdmi"
> -};

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 09/19] video: sunxi: de2: switch to public uclass functions
  2021-03-07  1:32   ` Andre Przywara
@ 2021-03-07  7:35     ` Jernej Škrabec
  2021-03-09  0:40       ` Andre Przywara
  0 siblings, 1 reply; 37+ messages in thread
From: Jernej Škrabec @ 2021-03-07  7:35 UTC (permalink / raw)
  To: u-boot

Dne nedelja, 07. marec 2021 ob 02:32:52 CET je Andre Przywara napisal(a):
> On Sat,  6 Mar 2021 20:54:27 +0100
> 
> Jernej Skrabec <jernej.skrabec@siol.net> wrote:
> > Currently DE2 driver uses functions which are defined in internal
> > headers. They are not meant to be used outside of uclass framework.
> > Switch DE2 driver to public ones. This has additional benefit that
> > device_probe doesn't need to be called manually.
> 
> Indeed, good solution: for the calls in _probe(), we call de2_init()
> right afterwards, which would explicitly call probe for the display, so
> this both saves this call and the usage of the internal function.
> For the calls in simplefb_setup: the DM framework checks if a device
> has already been activated, so there is no problem with double probes.
> 
> However, actually testing this on a Pine64-LTS revealed that this breaks
> on the A64: I only get a black screen (bisecting down to this commit).
> 
> I didn't investigate any further yet, just wanted to give a heads up.

Thanks! I'll check what's going on.

Best regards,
Jernej

> 
> Cheers,
> Andre
> 
> > Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> > ---
> > 
> >  drivers/video/sunxi/sunxi_de2.c | 29 ++++++++++-------------------
> >  1 file changed, 10 insertions(+), 19 deletions(-)
> > 
> > diff --git a/drivers/video/sunxi/sunxi_de2.c
> > b/drivers/video/sunxi/sunxi_de2.c index 6b836a011944..e02d359cd259 100644
> > --- a/drivers/video/sunxi/sunxi_de2.c
> > +++ b/drivers/video/sunxi/sunxi_de2.c
> > @@ -19,8 +19,6 @@
> > 
> >  #include <asm/io.h>
> >  #include <asm/arch/clock.h>
> >  #include <asm/arch/display2.h>
> > 
> > -#include <dm/device-internal.h>
> > -#include <dm/uclass-internal.h>
> > 
> >  #include <linux/bitops.h>
> >  #include "simplefb_common.h"
> > 
> > @@ -198,13 +196,6 @@ static int sunxi_de2_init(struct udevice *dev, ulong
> > fbbase,> 
> >  	disp_uc_plat->source_id = mux;
> > 
> > -	ret = device_probe(disp);
> > -	if (ret) {
> > -		debug("%s: device '%s' display won't probe (ret=%d)\n",
> > -		      __func__, dev->name, ret);
> > -		return ret;
> > -	}
> > -
> > 
> >  	ret = display_read_timing(disp, &timing);
> >  	if (ret) {
> >  	
> >  		debug("%s: Failed to read timings\n", __func__);
> > 
> > @@ -245,8 +236,8 @@ static int sunxi_de2_probe(struct udevice *dev)
> > 
> >  	if (!(gd->flags & GD_FLG_RELOC))
> >  	
> >  		return 0;
> > 
> > -	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
> > -					 "sunxi_lcd", &disp);
> > +	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> > +					  
DM_DRIVER_GET(sunxi_lcd), &disp);
> > 
> >  	if (!ret) {
> >  	
> >  		int mux;
> > 
> > @@ -262,8 +253,8 @@ static int sunxi_de2_probe(struct udevice *dev)
> > 
> >  	debug("%s: lcd display not found (ret=%d)\n", __func__, ret);
> > 
> > -	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
> > -					 "sunxi_dw_hdmi", 
&disp);
> > +	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> > +					  
DM_DRIVER_GET(sunxi_dw_hdmi), &disp);
> > 
> >  	if (!ret) {
> >  	
> >  		int mux;
> >  		if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
> > 
> > @@ -332,8 +323,8 @@ int sunxi_simplefb_setup(void *blob)
> > 
> >  		mux = 1;
> >  	
> >  	/* Skip simplefb setting if DE2 / HDMI is not present */
> > 
> > -	ret = uclass_find_device_by_name(UCLASS_VIDEO,
> > -					 "sunxi_de2", &de2);
> > +	ret = uclass_get_device_by_driver(UCLASS_VIDEO,
> > +					  
DM_DRIVER_GET(sunxi_de2), &de2);
> > 
> >  	if (ret) {
> >  	
> >  		debug("DE2 not present\n");
> >  		return 0;
> > 
> > @@ -342,8 +333,8 @@ int sunxi_simplefb_setup(void *blob)
> > 
> >  		return 0;
> >  	
> >  	}
> > 
> > -	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
> > -					 "sunxi_dw_hdmi", 
&hdmi);
> > +	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> > +					  
DM_DRIVER_GET(sunxi_dw_hdmi), &hdmi);
> > 
> >  	if (ret) {
> >  	
> >  		debug("HDMI not present\n");
> >  	
> >  	} else if (device_active(hdmi)) {
> > 
> > @@ -355,8 +346,8 @@ int sunxi_simplefb_setup(void *blob)
> > 
> >  		debug("HDMI present but not probed\n");
> >  	
> >  	}
> > 
> > -	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
> > -					 "sunxi_lcd", &lcd);
> > +	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> > +					  
DM_DRIVER_GET(sunxi_lcd), &lcd);
> > 
> >  	if (ret)
> >  	
> >  		debug("LCD not present\n");
> >  	
> >  	else if (device_active(lcd))

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 18/19] video: sunxi: Add DW HDMI PHY driver
  2021-03-06 19:54 ` [PATCH v2 18/19] video: sunxi: Add DW HDMI PHY driver Jernej Skrabec
@ 2021-03-08  7:57   ` Jagan Teki
  2021-03-09  5:38     ` Jernej Škrabec
  0 siblings, 1 reply; 37+ messages in thread
From: Jagan Teki @ 2021-03-08  7:57 UTC (permalink / raw)
  To: u-boot

On Sun, Mar 7, 2021 at 1:25 AM Jernej Skrabec <jernej.skrabec@siol.net> wrote:
>
> This commit adds standalone driver for DW HDMI PHY. It deprecates code
> which is included in sunxi dw-hdmi platform driver.
>
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> ---
>  arch/arm/mach-sunxi/Kconfig             |   1 +
>  drivers/video/sunxi/Makefile            |   2 +-
>  drivers/video/sunxi/sunxi_dw_hdmi_phy.c | 423 ++++++++++++++++++++++++
>  drivers/video/sunxi/sunxi_dw_hdmi_phy.h |  24 ++

Would be good if this PHY management code handles via drivers/phy.
Hope this would possible?

Jagan.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 15/19] clk: sunxi: add DE2 clock driver
  2021-03-06 19:54 ` [PATCH v2 15/19] clk: sunxi: add DE2 clock driver Jernej Skrabec
@ 2021-03-08  7:59   ` Jagan Teki
  0 siblings, 0 replies; 37+ messages in thread
From: Jagan Teki @ 2021-03-08  7:59 UTC (permalink / raw)
  To: u-boot

On Sun, Mar 7, 2021 at 1:25 AM Jernej Skrabec <jernej.skrabec@siol.net> wrote:
>
> Video driver currently manages clocks and resets by directly writing to
> registers. This is already a bit messy because each SoC has some
> specifics. It's much better to implement proper clock and reset driver
> which takes information from device tree file.
>
> Note that this driver is not perfect yet. It still sets PLL and parent
> by hand. Sunxi clock framework still doesn't know how to set parents or
> rates. However, this is already big step in right direction.
>
> Cc: Lukasz Majewski <lukma@denx.de>
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> ---

Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 14/19] clk: sunxi: Add DE2 and HDMI clocks to H3 and A64
  2021-03-06 19:54 ` [PATCH v2 14/19] clk: sunxi: Add DE2 and HDMI clocks to H3 and A64 Jernej Skrabec
@ 2021-03-08  8:00   ` Jagan Teki
  0 siblings, 0 replies; 37+ messages in thread
From: Jagan Teki @ 2021-03-08  8:00 UTC (permalink / raw)
  To: u-boot

On Sun, Mar 7, 2021 at 1:25 AM Jernej Skrabec <jernej.skrabec@siol.net> wrote:
>
> These clocks and resets are needed for video drivers.
>
> Cc: Lukasz Majewski <lukma@denx.de>
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> ---

Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 16/19] video: sunxi: de2: switch clock setup to DM model
  2021-03-06 19:54 ` [PATCH v2 16/19] video: sunxi: de2: switch clock setup to DM model Jernej Skrabec
@ 2021-03-08  8:02   ` Jagan Teki
  0 siblings, 0 replies; 37+ messages in thread
From: Jagan Teki @ 2021-03-08  8:02 UTC (permalink / raw)
  To: u-boot

On Sun, Mar 7, 2021 at 1:25 AM Jernej Skrabec <jernej.skrabec@siol.net> wrote:
>
> Now that proper DM clock and reset driver exists for Display Engine 2
> and 3, remove all clock and reset related code and use appropriate
> framework instead.
>
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> ---

Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 09/19] video: sunxi: de2: switch to public uclass functions
  2021-03-07  7:35     ` Jernej Škrabec
@ 2021-03-09  0:40       ` Andre Przywara
  2021-03-09  5:35         ` Jernej Škrabec
  0 siblings, 1 reply; 37+ messages in thread
From: Andre Przywara @ 2021-03-09  0:40 UTC (permalink / raw)
  To: u-boot

On Sun, 07 Mar 2021 08:35:23 +0100
Jernej ?krabec <jernej.skrabec@siol.net> wrote:

Hi,

> Dne nedelja, 07. marec 2021 ob 02:32:52 CET je Andre Przywara napisal(a):
> > On Sat,  6 Mar 2021 20:54:27 +0100
> > 
> > Jernej Skrabec <jernej.skrabec@siol.net> wrote:  
> > > Currently DE2 driver uses functions which are defined in internal
> > > headers. They are not meant to be used outside of uclass framework.
> > > Switch DE2 driver to public ones. This has additional benefit that
> > > device_probe doesn't need to be called manually.  
> > 
> > Indeed, good solution: for the calls in _probe(), we call de2_init()
> > right afterwards, which would explicitly call probe for the display, so
> > this both saves this call and the usage of the internal function.
> > For the calls in simplefb_setup: the DM framework checks if a device
> > has already been activated, so there is no problem with double probes.
> > 
> > However, actually testing this on a Pine64-LTS revealed that this breaks
> > on the A64: I only get a black screen (bisecting down to this commit).
> > 
> > I didn't investigate any further yet, just wanted to give a heads up.  
> 
> Thanks! I'll check what's going on.

I think I know what's going on, see below.

> >   
> > > Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> > > ---
> > > 
> > >  drivers/video/sunxi/sunxi_de2.c | 29 ++++++++++-------------------
> > >  1 file changed, 10 insertions(+), 19 deletions(-)
> > > 
> > > diff --git a/drivers/video/sunxi/sunxi_de2.c
> > > b/drivers/video/sunxi/sunxi_de2.c index 6b836a011944..e02d359cd259 100644
> > > --- a/drivers/video/sunxi/sunxi_de2.c
> > > +++ b/drivers/video/sunxi/sunxi_de2.c
> > > @@ -19,8 +19,6 @@
> > > 
> > >  #include <asm/io.h>
> > >  #include <asm/arch/clock.h>
> > >  #include <asm/arch/display2.h>
> > > 
> > > -#include <dm/device-internal.h>
> > > -#include <dm/uclass-internal.h>
> > > 
> > >  #include <linux/bitops.h>
> > >  #include "simplefb_common.h"
> > > 
> > > @@ -198,13 +196,6 @@ static int sunxi_de2_init(struct udevice *dev, ulong  
> > > fbbase,>   
> > >  	disp_uc_plat->source_id = mux;

The mux value is set *after* the call to uclass_find_device_by_name()
(or uclass_get_device_by_driver()) returned, and then we call this
function with it, which *used* to call probe().
Now probe is already called as part of uclass_get_device_by_driver(),
so *before* we had a chance to determine and set the mux value/
source_id.
For the H3/H5 it's 0, so it conveniently works with the probably zeroed
uc_plat structure there.

Not sure how to fix this, as we get a handle to the device only after
the uclass_find/get functions returned, so don't know where to set
source_id before that.

Shall this H3 vs. A64 check be moved into the HDMI driver and it's probe routine?

Cheers,
Andre

> > > 
> > > -	ret = device_probe(disp);
> > > -	if (ret) {
> > > -		debug("%s: device '%s' display won't probe (ret=%d)\n",
> > > -		      __func__, dev->name, ret);
> > > -		return ret;
> > > -	}
> > > -
> > > 
> > >  	ret = display_read_timing(disp, &timing);
> > >  	if (ret) {
> > >  	
> > >  		debug("%s: Failed to read timings\n", __func__);
> > > 
> > > @@ -245,8 +236,8 @@ static int sunxi_de2_probe(struct udevice *dev)
> > > 
> > >  	if (!(gd->flags & GD_FLG_RELOC))
> > >  	
> > >  		return 0;
> > > 
> > > -	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
> > > -					 "sunxi_lcd", &disp);
> > > +	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> > > +					    
> DM_DRIVER_GET(sunxi_lcd), &disp);
> > > 
> > >  	if (!ret) {
> > >  	
> > >  		int mux;
> > > 
> > > @@ -262,8 +253,8 @@ static int sunxi_de2_probe(struct udevice *dev)
> > > 
> > >  	debug("%s: lcd display not found (ret=%d)\n", __func__, ret);
> > > 
> > > -	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
> > > -					 "sunxi_dw_hdmi",   
> &disp);
> > > +	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> > > +					    
> DM_DRIVER_GET(sunxi_dw_hdmi), &disp);
> > > 
> > >  	if (!ret) {
> > >  	
> > >  		int mux;
> > >  		if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
> > > 
> > > @@ -332,8 +323,8 @@ int sunxi_simplefb_setup(void *blob)
> > > 
> > >  		mux = 1;
> > >  	
> > >  	/* Skip simplefb setting if DE2 / HDMI is not present */
> > > 
> > > -	ret = uclass_find_device_by_name(UCLASS_VIDEO,
> > > -					 "sunxi_de2", &de2);
> > > +	ret = uclass_get_device_by_driver(UCLASS_VIDEO,
> > > +					    
> DM_DRIVER_GET(sunxi_de2), &de2);
> > > 
> > >  	if (ret) {
> > >  	
> > >  		debug("DE2 not present\n");
> > >  		return 0;
> > > 
> > > @@ -342,8 +333,8 @@ int sunxi_simplefb_setup(void *blob)
> > > 
> > >  		return 0;
> > >  	
> > >  	}
> > > 
> > > -	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
> > > -					 "sunxi_dw_hdmi",   
> &hdmi);
> > > +	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> > > +					    
> DM_DRIVER_GET(sunxi_dw_hdmi), &hdmi);
> > > 
> > >  	if (ret) {
> > >  	
> > >  		debug("HDMI not present\n");
> > >  	
> > >  	} else if (device_active(hdmi)) {
> > > 
> > > @@ -355,8 +346,8 @@ int sunxi_simplefb_setup(void *blob)
> > > 
> > >  		debug("HDMI present but not probed\n");
> > >  	
> > >  	}
> > > 
> > > -	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
> > > -					 "sunxi_lcd", &lcd);
> > > +	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> > > +					    
> DM_DRIVER_GET(sunxi_lcd), &lcd);
> > > 
> > >  	if (ret)
> > >  	
> > >  		debug("LCD not present\n");
> > >  	
> > >  	else if (device_active(lcd))  
> 
> 
> 
> 

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 09/19] video: sunxi: de2: switch to public uclass functions
  2021-03-09  0:40       ` Andre Przywara
@ 2021-03-09  5:35         ` Jernej Škrabec
  0 siblings, 0 replies; 37+ messages in thread
From: Jernej Škrabec @ 2021-03-09  5:35 UTC (permalink / raw)
  To: u-boot

Dne torek, 09. marec 2021 ob 01:40:32 CET je Andre Przywara napisal(a):
> On Sun, 07 Mar 2021 08:35:23 +0100
> Jernej ?krabec <jernej.skrabec@siol.net> wrote:
> 
> Hi,
> 
> > Dne nedelja, 07. marec 2021 ob 02:32:52 CET je Andre Przywara napisal(a):
> > > On Sat,  6 Mar 2021 20:54:27 +0100
> > > 
> > > Jernej Skrabec <jernej.skrabec@siol.net> wrote:
> > > > Currently DE2 driver uses functions which are defined in internal
> > > > headers. They are not meant to be used outside of uclass framework.
> > > > Switch DE2 driver to public ones. This has additional benefit that
> > > > device_probe doesn't need to be called manually.
> > > 
> > > Indeed, good solution: for the calls in _probe(), we call de2_init()
> > > right afterwards, which would explicitly call probe for the display, so
> > > this both saves this call and the usage of the internal function.
> > > For the calls in simplefb_setup: the DM framework checks if a device
> > > has already been activated, so there is no problem with double probes.
> > > 
> > > However, actually testing this on a Pine64-LTS revealed that this breaks
> > > on the A64: I only get a black screen (bisecting down to this commit).
> > > 
> > > I didn't investigate any further yet, just wanted to give a heads up.
> > 
> > Thanks! I'll check what's going on.
> 
> I think I know what's going on, see below.
> 
> > > > Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> > > > ---
> > > > 
> > > >  drivers/video/sunxi/sunxi_de2.c | 29 ++++++++++-------------------
> > > >  1 file changed, 10 insertions(+), 19 deletions(-)
> > > > 
> > > > diff --git a/drivers/video/sunxi/sunxi_de2.c
> > > > b/drivers/video/sunxi/sunxi_de2.c index 6b836a011944..e02d359cd259
> > > > 100644
> > > > --- a/drivers/video/sunxi/sunxi_de2.c
> > > > +++ b/drivers/video/sunxi/sunxi_de2.c
> > > > @@ -19,8 +19,6 @@
> > > > 
> > > >  #include <asm/io.h>
> > > >  #include <asm/arch/clock.h>
> > > >  #include <asm/arch/display2.h>
> > > > 
> > > > -#include <dm/device-internal.h>
> > > > -#include <dm/uclass-internal.h>
> > > > 
> > > >  #include <linux/bitops.h>
> > > >  #include "simplefb_common.h"
> > > > 
> > > > @@ -198,13 +196,6 @@ static int sunxi_de2_init(struct udevice *dev,
> > > > ulong
> > > > fbbase,>
> > > > 
> > > >  	disp_uc_plat->source_id = mux;
> 
> The mux value is set *after* the call to uclass_find_device_by_name()
> (or uclass_get_device_by_driver()) returned, and then we call this
> function with it, which *used* to call probe().
> Now probe is already called as part of uclass_get_device_by_driver(),
> so *before* we had a chance to determine and set the mux value/
> source_id.
> For the H3/H5 it's 0, so it conveniently works with the probably zeroed
> uc_plat structure there.

Oh, thanks for looking into this!

> 
> Not sure how to fix this, as we get a handle to the device only after
> the uclass_find/get functions returned, so don't know where to set
> source_id before that.
> 
> Shall this H3 vs. A64 check be moved into the HDMI driver and it's probe
> routine?

This info shouldn't be needed once TCON is implemented as standalone driver 
probed via compatible string. I guess workaround can be implemented in HDMI 
driver to get TCON number from DT instead, although this is a bit clumsy.

Best regards,
Jernej

> 
> Cheers,
> Andre
> 
> > > > -	ret = device_probe(disp);
> > > > -	if (ret) {
> > > > -		debug("%s: device '%s' display won't probe (ret=%d)
\n",
> > > > -		      __func__, dev->name, ret);
> > > > -		return ret;
> > > > -	}
> > > > -
> > > > 
> > > >  	ret = display_read_timing(disp, &timing);
> > > >  	if (ret) {
> > > >  	
> > > >  		debug("%s: Failed to read timings\n", __func__);
> > > > 
> > > > @@ -245,8 +236,8 @@ static int sunxi_de2_probe(struct udevice *dev)
> > > > 
> > > >  	if (!(gd->flags & GD_FLG_RELOC))
> > > >  	
> > > >  		return 0;
> > > > 
> > > > -	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
> > > > -					 "sunxi_lcd", &disp);
> > > > +	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> > > > +
> > 
> > DM_DRIVER_GET(sunxi_lcd), &disp);
> > 
> > > >  	if (!ret) {
> > > >  	
> > > >  		int mux;
> > > > 
> > > > @@ -262,8 +253,8 @@ static int sunxi_de2_probe(struct udevice *dev)
> > > > 
> > > >  	debug("%s: lcd display not found (ret=%d)\n", __func__, ret);
> > > > 
> > > > -	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
> > > > -					 "sunxi_dw_hdmi",
> > 
> > &disp);
> > 
> > > > +	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> > > > +
> > 
> > DM_DRIVER_GET(sunxi_dw_hdmi), &disp);
> > 
> > > >  	if (!ret) {
> > > >  	
> > > >  		int mux;
> > > >  		if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
> > > > 
> > > > @@ -332,8 +323,8 @@ int sunxi_simplefb_setup(void *blob)
> > > > 
> > > >  		mux = 1;
> > > >  	
> > > >  	/* Skip simplefb setting if DE2 / HDMI is not present */
> > > > 
> > > > -	ret = uclass_find_device_by_name(UCLASS_VIDEO,
> > > > -					 "sunxi_de2", &de2);
> > > > +	ret = uclass_get_device_by_driver(UCLASS_VIDEO,
> > > > +
> > 
> > DM_DRIVER_GET(sunxi_de2), &de2);
> > 
> > > >  	if (ret) {
> > > >  	
> > > >  		debug("DE2 not present\n");
> > > >  		return 0;
> > > > 
> > > > @@ -342,8 +333,8 @@ int sunxi_simplefb_setup(void *blob)
> > > > 
> > > >  		return 0;
> > > >  	
> > > >  	}
> > > > 
> > > > -	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
> > > > -					 "sunxi_dw_hdmi",
> > 
> > &hdmi);
> > 
> > > > +	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> > > > +
> > 
> > DM_DRIVER_GET(sunxi_dw_hdmi), &hdmi);
> > 
> > > >  	if (ret) {
> > > >  	
> > > >  		debug("HDMI not present\n");
> > > >  	
> > > >  	} else if (device_active(hdmi)) {
> > > > 
> > > > @@ -355,8 +346,8 @@ int sunxi_simplefb_setup(void *blob)
> > > > 
> > > >  		debug("HDMI present but not probed\n");
> > > >  	
> > > >  	}
> > > > 
> > > > -	ret = uclass_find_device_by_name(UCLASS_DISPLAY,
> > > > -					 "sunxi_lcd", &lcd);
> > > > +	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> > > > +
> > 
> > DM_DRIVER_GET(sunxi_lcd), &lcd);
> > 
> > > >  	if (ret)
> > > >  	
> > > >  		debug("LCD not present\n");
> > > >  	
> > > >  	else if (device_active(lcd))

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 18/19] video: sunxi: Add DW HDMI PHY driver
  2021-03-08  7:57   ` Jagan Teki
@ 2021-03-09  5:38     ` Jernej Škrabec
  0 siblings, 0 replies; 37+ messages in thread
From: Jernej Škrabec @ 2021-03-09  5:38 UTC (permalink / raw)
  To: u-boot

Dne ponedeljek, 08. marec 2021 ob 08:57:31 CET je Jagan Teki napisal(a):
> On Sun, Mar 7, 2021 at 1:25 AM Jernej Skrabec <jernej.skrabec@siol.net> 
wrote:
> > This commit adds standalone driver for DW HDMI PHY. It deprecates code
> > which is included in sunxi dw-hdmi platform driver.
> > 
> > Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> > ---
> > 
> >  arch/arm/mach-sunxi/Kconfig             |   1 +
> >  drivers/video/sunxi/Makefile            |   2 +-
> >  drivers/video/sunxi/sunxi_dw_hdmi_phy.c | 423 ++++++++++++++++++++++++
> >  drivers/video/sunxi/sunxi_dw_hdmi_phy.h |  24 ++
> 
> Would be good if this PHY management code handles via drivers/phy.
> Hope this would possible?

You mean move this code there? Yeah, it's possible, but then we have to move 
sunxi_dw_hdmi_phy.h to general or arch includes folder, because it implements 
additional functionality which is not covered by general PHY interface.

Best regards,
Jernej

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 12/19] video: sunxi: de2: switch to DT probing
  2021-03-06 19:54 ` [PATCH v2 12/19] video: sunxi: de2: switch to DT probing Jernej Skrabec
@ 2021-04-06  1:09   ` Andre Przywara
  2021-04-06  7:14     ` Simon Glass
  0 siblings, 1 reply; 37+ messages in thread
From: Andre Przywara @ 2021-04-06  1:09 UTC (permalink / raw)
  To: u-boot

On Sat,  6 Mar 2021 20:54:30 +0100
Jernej Skrabec <jernej.skrabec@siol.net> wrote:

Hi Jernej,

(CC:ing Simon for some DM issues below)

> Currently DE2 driver is probed via driver info. Switch probing to device
> tree compatible string method.
> 
> Display is now searched via driver name which has same limitation as
> previous method. This can be improved only when all drivers in chain are
> probed via device tree compatible strings.

So on a first glance this looks alright (also the fixed version on your
github). However it doesn't work on the Pine64-LTS (or A64 in general),
and I identified at least two problems below:

> 
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> ---
>  drivers/video/sunxi/sunxi_de2.c | 88 +++++++++++++++++++--------------
>  1 file changed, 52 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c
> index e02d359cd259..81576e45e9ef 100644
> --- a/drivers/video/sunxi/sunxi_de2.c
> +++ b/drivers/video/sunxi/sunxi_de2.c
> @@ -31,6 +31,11 @@ enum {
>  	LCD_MAX_LOG2_BPP	= VIDEO_BPP32,
>  };
>  
> +struct sunxi_de2_data {
> +	int id;

nit: can you rename this to something less general, like mux or
pipeline_id?

> +	const char *disp_drv_name;
> +};
> +
>  static void sunxi_de2_composer_init(void)
>  {
>  	struct sunxi_ccm_reg * const ccm =
> @@ -228,51 +233,34 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase,
>  
>  static int sunxi_de2_probe(struct udevice *dev)
>  {
> +	const struct sunxi_de2_data *data =
> +		(const struct sunxi_de2_data *)dev_get_driver_data(dev);
>  	struct video_uc_plat *plat = dev_get_uclass_plat(dev);
>  	struct udevice *disp;
> -	int ret;
> +	int ret, index = 0;
>  
>  	/* Before relocation we don't need to do anything */
>  	if (!(gd->flags & GD_FLG_RELOC))
>  		return 0;
>  
> -	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> -					  DM_DRIVER_GET(sunxi_lcd), &disp);
> -	if (!ret) {
> -		int mux;
> +	while (!(ret = uclass_get_device(UCLASS_DISPLAY, index++, &disp))) {

So this call tries to enumerate all devices registered as
UCLASS_DISPLAY. For the A64 the sunxi_lcd driver provides one device,
however it only probes correctly when there is bridge configured (for
the Pinebook, for instance). There is code to read timings from DT,
but I don't find any of the required properties (simple-panel) in any
Allwinner DTs (using DE2, at least).
As a consequence the probe in sunxi_lcd.c fails (except for the
Pinebook), and it returns -ENODEV. This is unfortunately the same error
code that uclass_get_device_by_driver() returns when there are no
(more) devices providing UCLASS_DISPLAY, so the while loop stops here,
before having considered the HDMI devices (which are enumerated *after*
the LCD device). This is the same problem with your change to use
uclass_id_foreach_dev(), btw.

Not sure how to best solve this, it sounds like a general DM related
problem (failing probe() ending iterating all devices in one class).

I hacked this a bit (using a different error code in sunxi_lcd_probe()
and catching/translating this here), but this revealed another problem:
I only ever see the mixer0 device being probed (actually multiple
times). I could debug that both mixers are detected in the DT, created
as two devices and bound (using the right .id value and the right DT
offset), but only the first one is ever probed through this function
here. Unfortunately this is the wrong one (HDMI is on mixer1), so
de2_probe() fails :-(
Disabling mixer0 in the DT makes it work (on top of the hack above).

No real clue about this second problem, but I will debug further.

Cheers,
Andre


> +		if (strcmp(disp->driver->name, data->disp_drv_name))
> +			continue;
>  
> -		mux = 0;
> +		ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp,
> +				     data->id, false);
> +		if (ret)
> +			return ret;
>  
> -		ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux,
> -				     false);
> -		if (!ret) {
> -			video_set_flush_dcache(dev, 1);
> -			return 0;
> -		}
> -	}
> -
> -	debug("%s: lcd display not found (ret=%d)\n", __func__, ret);
> -
> -	ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> -					  DM_DRIVER_GET(sunxi_dw_hdmi), &disp);
> -	if (!ret) {
> -		int mux;
> -		if (IS_ENABLED(CONFIG_MACH_SUNXI_H3_H5))
> -			mux = 0;
> -		else
> -			mux = 1;
> +		video_set_flush_dcache(dev, 1);
>  
> -		ret = sunxi_de2_init(dev, plat->base, VIDEO_BPP32, disp, mux,
> -				     false);
> -		if (!ret) {
> -			video_set_flush_dcache(dev, 1);
> -			return 0;
> -		}
> +		return 0;
>  	}
>  
> -	debug("%s: hdmi display not found (ret=%d)\n", __func__, ret);
> +	debug("%s: %s not found (ret=%d)\n", __func__,
> +	      data->disp_drv_name, ret);
>  
> -	return -ENODEV;
> +	return ret;
>  }
>  
>  static int sunxi_de2_bind(struct udevice *dev)
> @@ -285,22 +273,50 @@ static int sunxi_de2_bind(struct udevice *dev)
>  	return 0;
>  }
>  
> +const struct sunxi_de2_data h3_mixer_0 = {
> +	.id = 0,
> +	.disp_drv_name = "sunxi_dw_hdmi",
> +};
> +
> +const struct sunxi_de2_data a64_mixer_0 = {
> +	.id = 0,
> +	.disp_drv_name = "sunxi_lcd",
> +};
> +
> +const struct sunxi_de2_data a64_mixer_1 = {
> +	.id = 1,
> +	.disp_drv_name = "sunxi_dw_hdmi",
> +};
> +
> +static const struct udevice_id sunxi_de2_ids[] = {
> +	{
> +		.compatible = "allwinner,sun8i-h3-de2-mixer-0",
> +		.data = (ulong)&h3_mixer_0,
> +	},
> +	{
> +		.compatible = "allwinner,sun50i-a64-de2-mixer-0",
> +		.data = (ulong)&a64_mixer_0,
> +	},
> +	{
> +		.compatible = "allwinner,sun50i-a64-de2-mixer-1",
> +		.data = (ulong)&a64_mixer_1,
> +	},
> +	{ }
> +};
> +
>  static const struct video_ops sunxi_de2_ops = {
>  };
>  
>  U_BOOT_DRIVER(sunxi_de2) = {
>  	.name	= "sunxi_de2",
>  	.id	= UCLASS_VIDEO,
> +	.of_match = sunxi_de2_ids,
>  	.ops	= &sunxi_de2_ops,
>  	.bind	= sunxi_de2_bind,
>  	.probe	= sunxi_de2_probe,
>  	.flags	= DM_FLAG_PRE_RELOC,
>  };
>  
> -U_BOOT_DRVINFO(sunxi_de2) = {
> -	.name = "sunxi_de2"
> -};
> -
>  /*
>   * Simplefb support.
>   */

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 11/19] video: sunxi: dw-hdmi: read address from DT node
  2021-03-06 19:54 ` [PATCH v2 11/19] video: sunxi: dw-hdmi: read address from DT node Jernej Skrabec
@ 2021-04-06  1:09   ` Andre Przywara
  0 siblings, 0 replies; 37+ messages in thread
From: Andre Przywara @ 2021-04-06  1:09 UTC (permalink / raw)
  To: u-boot

On Sat,  6 Mar 2021 20:54:29 +0100
Jernej Skrabec <jernej.skrabec@siol.net> wrote:

> Currently HDMI controller MMIO address is hardcoded. Change that so
> address is read from DT node. That will make adding support for new
> variants a bit easier.
> 
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>

Checked the transformations, and it's still working (after fixing the
mux problem with your new patch in your github).

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Thanks,
Andre

> ---
>  drivers/video/sunxi/sunxi_dw_hdmi.c | 38 ++++++++++++++++++-----------
>  1 file changed, 24 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c
> index 6f77b2a43b40..0744954fa15f 100644
> --- a/drivers/video/sunxi/sunxi_dw_hdmi.c
> +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c
> @@ -57,10 +57,10 @@ static int sunxi_dw_hdmi_get_divider(uint clock)
>  		return 1;
>  }
>  
> -static void sunxi_dw_hdmi_phy_init(void)
> +static void sunxi_dw_hdmi_phy_init(struct dw_hdmi *hdmi)
>  {
>  	struct sunxi_hdmi_phy * const phy =
> -		(struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS);
> +		(struct sunxi_hdmi_phy *)(hdmi->ioaddr + HDMI_PHY_OFFS);
>  	unsigned long tmo;
>  	u32 tmp;
>  
> @@ -114,10 +114,10 @@ static void sunxi_dw_hdmi_phy_init(void)
>  	writel(0x42494E47, &phy->unscramble);
>  }
>  
> -static void sunxi_dw_hdmi_phy_set(uint clock, int phy_div)
> +static void sunxi_dw_hdmi_phy_set(struct dw_hdmi *hdmi, uint clock, int phy_div)
>  {
>  	struct sunxi_hdmi_phy * const phy =
> -		(struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS);
> +		(struct sunxi_hdmi_phy *)(hdmi->ioaddr + HDMI_PHY_OFFS);
>  	int div = sunxi_dw_hdmi_get_divider(clock);
>  	u32 tmp;
>  
> @@ -271,7 +271,7 @@ static int sunxi_dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock)
>  	int phy_div;
>  
>  	sunxi_dw_hdmi_pll_set(mpixelclock / 1000, &phy_div);
> -	sunxi_dw_hdmi_phy_set(mpixelclock, phy_div);
> +	sunxi_dw_hdmi_phy_set(hdmi, mpixelclock, phy_div);
>  
>  	return 0;
>  }
> @@ -292,9 +292,9 @@ static bool sunxi_dw_hdmi_mode_valid(struct udevice *dev,
>  static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp,
>  				const struct display_timing *edid)
>  {
> -	struct sunxi_hdmi_phy * const phy =
> -		(struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS);
>  	struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev);
> +	struct sunxi_hdmi_phy * const phy =
> +		(struct sunxi_hdmi_phy *)(priv->hdmi.ioaddr + HDMI_PHY_OFFS);
>  	int ret;
>  
>  	ret = dw_hdmi_enable(&priv->hdmi, edid);
> @@ -316,12 +316,26 @@ static int sunxi_dw_hdmi_enable(struct udevice *dev, int panel_bpp,
>  	 * again or othwerwise BSP driver won't work. Dummy read is
>  	 * needed or otherwise last write doesn't get written correctly.
>  	 */
> -	(void)readb(SUNXI_HDMI_BASE);
> +	(void)readb(priv->hdmi.ioaddr);
>  	writel(0, &phy->unscramble);
>  
>  	return 0;
>  }
>  
> +static int sunxi_dw_hdmi_of_to_plat(struct udevice *dev)
> +{
> +	struct sunxi_dw_hdmi_priv *priv = dev_get_priv(dev);
> +	struct dw_hdmi *hdmi = &priv->hdmi;
> +
> +	hdmi->ioaddr = (ulong)dev_read_addr(dev);
> +	hdmi->i2c_clk_high = 0xd8;
> +	hdmi->i2c_clk_low = 0xfe;
> +	hdmi->reg_io_width = 1;
> +	hdmi->phy_set = sunxi_dw_hdmi_phy_cfg;
> +
> +	return 0;
> +}
> +
>  static int sunxi_dw_hdmi_probe(struct udevice *dev)
>  {
>  	struct display_plat *uc_plat = dev_get_uclass_plat(dev);
> @@ -346,13 +360,8 @@ static int sunxi_dw_hdmi_probe(struct udevice *dev)
>  	/* Clock on */
>  	setbits_le32(&ccm->hdmi_clk_cfg, CCM_HDMI_CTRL_GATE);
>  
> -	sunxi_dw_hdmi_phy_init();
> +	sunxi_dw_hdmi_phy_init(&priv->hdmi);
>  
> -	priv->hdmi.ioaddr = SUNXI_HDMI_BASE;
> -	priv->hdmi.i2c_clk_high = 0xd8;
> -	priv->hdmi.i2c_clk_low = 0xfe;
> -	priv->hdmi.reg_io_width = 1;
> -	priv->hdmi.phy_set = sunxi_dw_hdmi_phy_cfg;
>  	priv->mux = uc_plat->source_id;
>  
>  	ret = dw_hdmi_phy_wait_for_hpd(&priv->hdmi);
> @@ -382,6 +391,7 @@ U_BOOT_DRIVER(sunxi_dw_hdmi) = {
>  	.id	= UCLASS_DISPLAY,
>  	.of_match = sunxi_dw_hdmi_ids,
>  	.ops	= &sunxi_dw_hdmi_ops,
> +	.of_to_plat = sunxi_dw_hdmi_of_to_plat,
>  	.probe	= sunxi_dw_hdmi_probe,
>  	.priv_auto	= sizeof(struct sunxi_dw_hdmi_priv),
>  };

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 13/19] video: sunxi: de2: read address from DT node
  2021-03-06 19:54 ` [PATCH v2 13/19] video: sunxi: de2: read address from DT node Jernej Skrabec
@ 2021-04-06  1:10   ` Andre Przywara
  0 siblings, 0 replies; 37+ messages in thread
From: Andre Przywara @ 2021-04-06  1:10 UTC (permalink / raw)
  To: u-boot

On Sat,  6 Mar 2021 20:54:31 +0100
Jernej Skrabec <jernej.skrabec@siol.net> wrote:

> Currently DE2 uses hardcoded address based on SoC for which U-Boot is
> built. Read it from DT instead so there is no need to specify it when
> support for new SoC is added.
> 
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>

Looks alright. Since this was the only user of SUNXI_DE2_MUX[01]_BASE,
I wonder if we should remove those symbols from display2.h, to avoid
future code using them?

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Cheers,
Andre


> ---
>  drivers/video/sunxi/sunxi_de2.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c
> index 81576e45e9ef..f6c8ca075aba 100644
> --- a/drivers/video/sunxi/sunxi_de2.c
> +++ b/drivers/video/sunxi/sunxi_de2.c
> @@ -64,11 +64,10 @@ static void sunxi_de2_composer_init(void)
>  	setbits_le32(&ccm->de_clk_cfg, CCM_DE2_CTRL_GATE);
>  }
>  
> -static void sunxi_de2_mode_set(int mux, const struct display_timing *mode,
> +static void sunxi_de2_mode_set(ulong de_mux_base, int mux,
> +			       const struct display_timing *mode,
>  			       int bpp, ulong address, bool is_composite)
>  {
> -	ulong de_mux_base = (mux == 0) ?
> -			    SUNXI_DE2_MUX0_BASE : SUNXI_DE2_MUX1_BASE;
>  	struct de_clk * const de_clk_regs =
>  		(struct de_clk *)(SUNXI_DE2_BASE);
>  	struct de_glb * const de_glb_regs =
> @@ -208,7 +207,8 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase,
>  	}
>  
>  	sunxi_de2_composer_init();
> -	sunxi_de2_mode_set(mux, &timing, 1 << l2bpp, fbbase, is_composite);
> +	sunxi_de2_mode_set((ulong)dev_read_addr(dev), mux, &timing,
> +			   1 << l2bpp, fbbase, is_composite);
>  
>  	ret = display_enable(disp, 1 << l2bpp, &timing);
>  	if (ret) {

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH v2 12/19] video: sunxi: de2: switch to DT probing
  2021-04-06  1:09   ` Andre Przywara
@ 2021-04-06  7:14     ` Simon Glass
  0 siblings, 0 replies; 37+ messages in thread
From: Simon Glass @ 2021-04-06  7:14 UTC (permalink / raw)
  To: u-boot

Hi Andre,

On Tue, 6 Apr 2021 at 13:09, Andre Przywara <andre.przywara@arm.com> wrote:
>
> On Sat,  6 Mar 2021 20:54:30 +0100
> Jernej Skrabec <jernej.skrabec@siol.net> wrote:
>
> Hi Jernej,
>
> (CC:ing Simon for some DM issues below)
>
> > Currently DE2 driver is probed via driver info. Switch probing to device
> > tree compatible string method.
> >
> > Display is now searched via driver name which has same limitation as
> > previous method. This can be improved only when all drivers in chain are
> > probed via device tree compatible strings.
>
> So on a first glance this looks alright (also the fixed version on your
> github). However it doesn't work on the Pine64-LTS (or A64 in general),
> and I identified at least two problems below:
>
> >
> > Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> > ---
> >  drivers/video/sunxi/sunxi_de2.c | 88 +++++++++++++++++++--------------
> >  1 file changed, 52 insertions(+), 36 deletions(-)
> >
> > diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c
> > index e02d359cd259..81576e45e9ef 100644
> > --- a/drivers/video/sunxi/sunxi_de2.c
> > +++ b/drivers/video/sunxi/sunxi_de2.c
> > @@ -31,6 +31,11 @@ enum {
> >       LCD_MAX_LOG2_BPP        = VIDEO_BPP32,
> >  };
> >
> > +struct sunxi_de2_data {
> > +     int id;
>
> nit: can you rename this to something less general, like mux or
> pipeline_id?
>
> > +     const char *disp_drv_name;
> > +};
> > +
> >  static void sunxi_de2_composer_init(void)
> >  {
> >       struct sunxi_ccm_reg * const ccm =
> > @@ -228,51 +233,34 @@ static int sunxi_de2_init(struct udevice *dev, ulong fbbase,
> >
> >  static int sunxi_de2_probe(struct udevice *dev)
> >  {
> > +     const struct sunxi_de2_data *data =
> > +             (const struct sunxi_de2_data *)dev_get_driver_data(dev);
> >       struct video_uc_plat *plat = dev_get_uclass_plat(dev);
> >       struct udevice *disp;
> > -     int ret;
> > +     int ret, index = 0;
> >
> >       /* Before relocation we don't need to do anything */
> >       if (!(gd->flags & GD_FLG_RELOC))
> >               return 0;
> >
> > -     ret = uclass_get_device_by_driver(UCLASS_DISPLAY,
> > -                                       DM_DRIVER_GET(sunxi_lcd), &disp);
> > -     if (!ret) {
> > -             int mux;
> > +     while (!(ret = uclass_get_device(UCLASS_DISPLAY, index++, &disp))) {
>
> So this call tries to enumerate all devices registered as
> UCLASS_DISPLAY. For the A64 the sunxi_lcd driver provides one device,
> however it only probes correctly when there is bridge configured (for
> the Pinebook, for instance). There is code to read timings from DT,
> but I don't find any of the required properties (simple-panel) in any
> Allwinner DTs (using DE2, at least).
> As a consequence the probe in sunxi_lcd.c fails (except for the
> Pinebook), and it returns -ENODEV. This is unfortunately the same error
> code that uclass_get_device_by_driver() returns when there are no
> (more) devices providing UCLASS_DISPLAY, so the while loop stops here,
> before having considered the HDMI devices (which are enumerated *after*
> the LCD device). This is the same problem with your change to use
> uclass_id_foreach_dev(), btw.

Well, good to check the error to something different. The -ENODEV
error is reserved for driver model. It can be returned by the bind()
method, but not probe().

>
> Not sure how to best solve this, it sounds like a general DM related
> problem (failing probe() ending iterating all devices in one class).

That's intended though. I suppose we could change it. But you can
iterate through devices with uclass_first_device_err() if you want to
do them all..

Is this in core DM code or somewhere else?

>
> I hacked this a bit (using a different error code in sunxi_lcd_probe()
> and catching/translating this here), but this revealed another problem:
> I only ever see the mixer0 device being probed (actually multiple
> times). I could debug that both mixers are detected in the DT, created
> as two devices and bound (using the right .id value and the right DT
> offset), but only the first one is ever probed through this function
> here. Unfortunately this is the wrong one (HDMI is on mixer1), so
> de2_probe() fails :-(
> Disabling mixer0 in the DT makes it work (on top of the hack above).
>
> No real clue about this second problem, but I will debug further.
>
[..]

Regards,
Simon

^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2021-04-06  7:14 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-06 19:54 [PATCH v2 00/19] video: sunxi: rework DE2 driver Jernej Skrabec
2021-03-06 19:54 ` [PATCH v2 01/19] sunxi: video: select dw-hdmi in Kconfig, not Makefile Jernej Skrabec
2021-03-06 19:54 ` [PATCH v2 02/19] video: sunxi: Add mode_valid callback to sunxi_dw_hdmi Jernej Skrabec
2021-03-06 19:54 ` [PATCH v2 03/19] common: edid: check for digital display earlier Jernej Skrabec
2021-03-06 19:54 ` [PATCH v2 04/19] common: edid: extract code for detailed timing search Jernej Skrabec
2021-03-07  1:29   ` Andre Przywara
2021-03-06 19:54 ` [PATCH v2 05/19] common: edid: Search for valid timing in extension block Jernej Skrabec
2021-03-06 19:54 ` [PATCH v2 06/19] video: sunxi: Use DW-HDMI hpd function Jernej Skrabec
2021-03-07  1:30   ` Andre Przywara
2021-03-06 19:54 ` [PATCH v2 07/19] video: sunxi: Remove check for ddc-i2c-bus property Jernej Skrabec
2021-03-06 19:54 ` [PATCH v2 08/19] video: sunxi: Remove TV probe from DE2 Jernej Skrabec
2021-03-07  1:31   ` Andre Przywara
2021-03-06 19:54 ` [PATCH v2 09/19] video: sunxi: de2: switch to public uclass functions Jernej Skrabec
2021-03-07  1:32   ` Andre Przywara
2021-03-07  7:35     ` Jernej Škrabec
2021-03-09  0:40       ` Andre Przywara
2021-03-09  5:35         ` Jernej Škrabec
2021-03-06 19:54 ` [PATCH v2 10/19] video: sunxi: dw-hdmi: probe driver by compatible Jernej Skrabec
2021-03-07  1:33   ` Andre Przywara
2021-03-06 19:54 ` [PATCH v2 11/19] video: sunxi: dw-hdmi: read address from DT node Jernej Skrabec
2021-04-06  1:09   ` Andre Przywara
2021-03-06 19:54 ` [PATCH v2 12/19] video: sunxi: de2: switch to DT probing Jernej Skrabec
2021-04-06  1:09   ` Andre Przywara
2021-04-06  7:14     ` Simon Glass
2021-03-06 19:54 ` [PATCH v2 13/19] video: sunxi: de2: read address from DT node Jernej Skrabec
2021-04-06  1:10   ` Andre Przywara
2021-03-06 19:54 ` [PATCH v2 14/19] clk: sunxi: Add DE2 and HDMI clocks to H3 and A64 Jernej Skrabec
2021-03-08  8:00   ` Jagan Teki
2021-03-06 19:54 ` [PATCH v2 15/19] clk: sunxi: add DE2 clock driver Jernej Skrabec
2021-03-08  7:59   ` Jagan Teki
2021-03-06 19:54 ` [PATCH v2 16/19] video: sunxi: de2: switch clock setup to DM model Jernej Skrabec
2021-03-08  8:02   ` Jagan Teki
2021-03-06 19:54 ` [PATCH v2 17/19] video: dw-hdmi: modify phy init callback to include full timings Jernej Skrabec
2021-03-06 19:54 ` [PATCH v2 18/19] video: sunxi: Add DW HDMI PHY driver Jernej Skrabec
2021-03-08  7:57   ` Jagan Teki
2021-03-09  5:38     ` Jernej Škrabec
2021-03-06 19:54 ` [PATCH v2 19/19] video: sunxi: dw-hdmi: Use new " Jernej Skrabec

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.