浏览代码

hdmi: add hdmi driver in uboot

hdmi can show a bitmap logo while uboot start
and the default resolution is 1920x1080@60fps

Signed-off-by: keith.zhao<keith.zhao@statfivetech.com>
keith.zhao 1 年之前
父节点
当前提交
34c5d49814

+ 1 - 1
drivers/video/raydium-rm68200-starfive.c

@@ -311,7 +311,7 @@ static int rm68200_panel_probe(struct udevice *dev)
 	   break;
 
 	   default:
-		   printf("Unknown Atmel firmware revision: 0x%02x\n", reg_value);
+		   debug("Unknown Atmel firmware revision: 0x%02x\n", reg_value);
 		   return -ENODEV;
 	}
 

+ 521 - 18
drivers/video/starfive/sf_hdmi.c

@@ -1,8 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH
+ * Copyright (c) 2023 keith.zhao@starfivetech.com
  */
 
+#include <asm/gpio.h>
+#include <asm/io.h>
 #include <common.h>
 #include <clk.h>
 #include <display.h>
@@ -11,48 +13,549 @@
 #include <edid.h>
 #include <regmap.h>
 #include <syscon.h>
-#include <asm/gpio.h>
-#include <asm/io.h>
+
 #include <power/regulator.h>
+#include <linux/delay.h>
+
 #include "sf_hdmi.h"
 
-static int rk3399_hdmi_enable(struct udevice *dev, int panel_bpp,
+static int hdmi_read(struct sf_hdmi_priv *priv,uint32_t addr)
+{
+	return readl(priv->base + (addr) * 0x04);
+
+}
+static void hdmi_write(struct sf_hdmi_priv *priv,int val, uint32_t addr)
+{
+	writel(val, priv->base + (addr) * 0x04);
+}
+
+static void inno_hdmi_detect(struct sf_hdmi_priv *priv)
+{
+	int val;
+	val = hdmi_read(priv,0x1b0);
+	val |= 0x4;
+	hdmi_write(priv,val, 0x1b0); //set 0x1b0[2] to 1'b1
+	hdmi_write(priv,0xf, 0x1cc); //set 0x1cc[3:0] to 4'b1111
+	//while(!(hdmi_read(0x1cd)  == 0x55));
+
+	/*turn on pre-PLL*/
+	val = hdmi_read(priv,0x1a0);
+	val &= ~(0x1);
+	hdmi_write(priv,val, 0x1a0);
+	/*turn on post-PLL*/
+	val = hdmi_read(priv,0x1aa);
+	val &= ~(0x1);
+	hdmi_write(priv,val, 0x1aa);
+
+	/*wait for pre-PLL and post-PLL lock*/
+	while(!(hdmi_read(priv,0x1a9) & 0x1));
+	while(!(hdmi_read(priv,0x1af) & 0x1));
+
+	/*turn on LDO*/
+	hdmi_write(priv,0x7, 0x1b4);
+	/*turn on serializer*/
+	hdmi_write(priv,0x70, 0x1be);
+}
+
+static void inno_hdmi_tx_phy_power_down(struct sf_hdmi_priv *priv)
+{
+	hdmi_write(priv,0x63, 0x00);
+}
+
+static void inno_hdmi_config_1440x480i60(struct sf_hdmi_priv *priv)
+{
+#ifdef REF_CLK_27M
+	const reg_value_t cfg_pll_data[] = {
+		/* config pll: 1440x480i, 60hz*/
+		{0x1a0, 0x01},
+		{0x1aa, 0x0f},
+		{0x1a1, 0x01},
+		{0x1a2, 0xf0},
+		{0x1a3, 0x28},
+		{0x1a4, 0x35},
+		{0x1a5, 0x61},
+		{0x1a6, 0x64},
+		{0x1ab, 0x01},
+		{0x1ac, 0x28},
+		{0x1ad, 0x03},
+		{0x1aa, 0x0e},
+		{0x1a0, 0x00},
+	};
+#else
+	const reg_value_t cfg_pll_data[] = {
+		/* config pll: 1440x480i, 60hz*/
+		{0x1a0, 0x01},
+		{0x1aa, 0x0f},
+		{0x1a1, 0x01},
+		{0x1a2, 0xf0},
+		{0x1a3, 0x64},
+		{0x1a4, 0x2f},
+		{0x1a5, 0x6c},
+		{0x1a6, 0x64},
+		{0x1ab, 0x01},
+		{0x1ac, 0x50},
+		{0x1ad, 0x07},
+		{0x1aa, 0x0e},
+		{0x1a0, 0x00},
+	};
+#endif
+	for (int i = 0; i < sizeof(cfg_pll_data)/sizeof(reg_value_t); i++) {
+		hdmi_write(priv, cfg_pll_data[i].value, cfg_pll_data[i].reg);
+	}
+	return;
+}
+
+static void inno_hdmi_config_640x480p60(struct sf_hdmi_priv *priv)
+{
+#ifdef REF_CLK_27M
+	const reg_value_t cfg_pll_data[] = {
+		/* config pll: 640x480p, 60hz*/
+		{0x1a0, 0x01},
+		{0x1aa, 0x0f},
+		{0x1a1, 0x01},
+		{0x1a2, 0xc0},
+		{0x1a3, 0x25},
+		{0x1a4, 0x35},
+		{0x1a5, 0x61},
+		{0x1a6, 0x64},
+		{0x1ab, 0x01},
+		{0x1ac, 0x28},
+		{0x1ad, 0x03},
+		{0x1aa, 0x0e},
+		{0x1a0, 0x00},
+		{0x1d1, 0x55},
+		{0x1d2, 0x55},
+		{0x1d3, 0x55},
+	};
+#else
+	const reg_value_t cfg_pll_data[] = {
+		/* config pll: 640x480p, 60hz*/
+		{0x1a0, 0x01},
+		//{0x1aa, 0x0f},
+		{0x1a1, 0x01},
+		{0x1a2, 0xf0},
+		{0x1a3, 0x64},
+		{0x1a4, 0x2f},
+		//{0x1a4, 0x2a},
+		{0x1a5, 0x6c},
+		{0x1a6, 0x64},
+		{0x1ab, 0x01},
+		{0x1ac, 0x50},
+		//{0x1ad, 0x07},
+		{0x1ad, 0x0d},
+		{0x1aa, 0x0e},
+		{0x1a0, 0x00},
+	};
+#endif
+	for (int i = 0; i < sizeof(cfg_pll_data)/sizeof(reg_value_t); i++) {
+		hdmi_write(priv, cfg_pll_data[i].value, cfg_pll_data[i].reg);
+	}
+	return;
+}
+
+static void inno_hdmi_config_720x480p60(struct sf_hdmi_priv *priv)
+{
+#ifdef REF_CLK_27M
+	const reg_value_t cfg_pll_data[] = {
+		/* config pll: 720x480p, 60hz*/
+		{0x1a0, 0x01},
+		{0x1aa, 0x0f},
+		{0x1a1, 0x01},
+		{0x1a2, 0xf0},
+		{0x1a3, 0x28},
+		{0x1a4, 0x35},
+		{0x1a5, 0x61},
+		{0x1a6, 0x64},
+		{0x1ab, 0x01},
+		{0x1ac, 0x28},
+		{0x1ad, 0x03},
+		{0x1aa, 0x0e},
+		{0x1a0, 0x00},
+	};
+#else
+	const reg_value_t cfg_pll_data[] = {
+		/* config pll: 640x480p, 60hz*/
+		{0x1a0, 0x01},
+		{0x1aa, 0x0f},
+		{0x1a1, 0x01},
+		{0x1a2, 0xf0},
+		{0x1a3, 0x64},
+		{0x1a4, 0x2f},
+		{0x1a5, 0x6c},
+		{0x1a6, 0x64},
+		{0x1ab, 0x01},
+		{0x1ac, 0x50},
+		{0x1ad, 0x07},
+		{0x1aa, 0x0e},
+		{0x1a0, 0x00},
+	};
+#endif
+	for (int i = 0; i < sizeof(cfg_pll_data)/sizeof(reg_value_t); i++) {
+		hdmi_write(priv,cfg_pll_data[i].value, cfg_pll_data[i].reg);
+	}
+	return;
+}
+
+
+static void inno_hdmi_config_1280x720p60(struct sf_hdmi_priv *priv)
+{
+#ifdef REF_CLK_27M
+	const reg_value_t cfg_pll_data[] = {
+		/* config pll: 720p, 60hz*/
+		{0x1a0, 0x01},
+		{0x1aa, 0x0f},
+		{0x1a1, 0x01},
+		{0x1a2, 0xf0},
+		{0x1a3, 0x37},
+		{0x1a4, 0x30},
+		{0x1a5, 0x61},
+		{0x1a6, 0x42},
+		{0x1ab, 0x01},
+		{0x1ac, 0x14},
+		{0x1ad, 0x01},
+		{0x1aa, 0x0e},
+		{0x1a0, 0x00},
+	};
+#else
+	const reg_value_t cfg_pll_data[] = {
+		/* config pll: 720p, 60hz*/
+		{0x1a0, 0x01},
+		{0x1aa, 0x0f},
+		{0x1a1, 0x01},
+		{0x1a2, 0xf0},
+		{0x1a3, 0x63},
+		//{0x1a4, 0x1f},
+		{0x1a4, 0x1a},
+		//{0x1a5, 0x48},
+		{0x1a5, 0x41},
+		{0x1a6, 0x64},
+		{0x1ab, 0x01},
+		{0x1ac, 0x14},
+		{0x1ad, 0x01},
+		{0x1aa, 0x0e},
+		{0x1a0, 0x00},
+	};
+#endif
+	for (int i = 0; i < sizeof(cfg_pll_data)/sizeof(reg_value_t); i++) {
+		hdmi_write(priv, cfg_pll_data[i].value, cfg_pll_data[i].reg);
+	}
+	return;
+}
+
+static void inno_hdmi_config_1920x1080p60(struct sf_hdmi_priv *priv)
+{
+#ifdef REF_CLK_27M
+	const reg_value_t cfg_pll_data[] = {
+		/* config pll: 1080p, 60hz*/
+		{0x1a0, 0x01},
+		{0x1aa, 0x0f},
+		{0x1a1, 0x01},
+		{0x1a2, 0xf0},
+		{0x1a3, 0x6e},
+		{0x1a4, 0x30},
+		{0x1a5, 0x60},
+		{0x1a6, 0x42},
+		{0x1ab, 0x04},
+		{0x1ac, 0x50},
+		{0x1ad, 0x01},
+		{0x1aa, 0x0e},
+		{0x1a0, 0x00},
+	};
+#else
+	const reg_value_t cfg_pll_data[] = {
+		/* config pll: 1080p, 60hz*/
+		{0x1a0, 0x01},
+		{0x1aa, 0x0f},
+		{0x1a1, 0x01},
+		{0x1a2, 0xf0},
+		{0x1a3, 0x63},
+		{0x1a4, 0x15},
+		{0x1a5, 0x41},
+		{0x1a6, 0x42},
+		{0x1ab, 0x01},
+		//{0x1ac, 0x0a},
+		{0x1ac, 0x14},
+		//{0x1ad, 0x00},
+		{0x1ad, 0x01},
+		{0x1aa, 0x0e},
+		{0x1a0, 0x00},
+	};
+#endif
+	for (int i = 0; i < sizeof(cfg_pll_data)/sizeof(reg_value_t); i++) {
+		hdmi_write(priv, cfg_pll_data[i].value, cfg_pll_data[i].reg);
+	}
+	return;
+}
+
+static void inno_hdmi_config_3840x2160p60(struct sf_hdmi_priv *priv)
+{
+#ifdef REF_CLK_27M
+	const reg_value_t cfg_pll_data[] = {
+		/* config pll: 4K, 60hz*/
+		{0x1a0, 0x01},
+		{0x1aa, 0x0f},
+		{0x1a1, 0x01},
+		{0x1a2, 0xf0},
+		{0x1a3, 0x63},
+		{0x1a4, 0x08},
+		{0x1a5, 0x01},
+		{0x1a6, 0x21},
+		{0x1ab, 0x04},
+		{0x1ac, 0x14},
+		{0x1ad, 0x00},
+		{0x1aa, 0x02},
+		{0x1a0, 0x00},
+	};
+#else
+	const reg_value_t cfg_pll_data[] = {
+		/* config pll: 4K, 60hz*/
+		{0x1a0, 0x01},
+		{0x1aa, 0x0f},
+		{0x1a1, 0x01},
+		{0x1a2, 0xf0},
+		{0x1a3, 0x63},
+		{0x1a4, 0x08},
+		{0x1a5, 0x01},
+		{0x1a6, 0x21},
+		{0x1ab, 0x04},
+		{0x1ac, 0x14},
+		{0x1ad, 0x00},
+		{0x1aa, 0x02},
+		{0x1a0, 0x00},
+	};
+#endif
+	for (int i = 0; i < sizeof(cfg_pll_data)/sizeof(reg_value_t); i++) {
+		hdmi_write(priv, cfg_pll_data[i].value, cfg_pll_data[i].reg);
+	}
+	return;
+}
+
+static void inno_hdmi_config_3840x2160p30(struct sf_hdmi_priv *priv)
+{
+#ifdef REF_CLK_27M
+	const reg_value_t cfg_pll_data[] = {
+		/* config pll: 4K, 30hz*/
+		{0x1a0, 0x01},
+		{0x1aa, 0x03},
+		{0x1a1, 0x01},
+		{0x1a2, 0xf0},
+		{0x1a3, 0x58},
+		{0x1a4, 0x10},
+		{0x1a5, 0x41},
+		{0x1a6, 0x21},
+		{0x1ab, 0x04},
+		{0x1ac, 0x14},
+		{0x1ad, 0x00},
+		{0x1aa, 0x02},
+		{0x1a0, 0x00},
+	};
+#else
+	const reg_value_t cfg_pll_data[] = {
+		/* config pll: 4K, 30hz*/
+		{0x1a0, 0x01},
+		{0x1aa, 0x0f},
+		{0x1a1, 0x01},
+		{0x1a2, 0xf0},
+		{0x1a3, 0x63},
+		{0x1a4, 0x10},
+		{0x1a5, 0x41},
+		{0x1a6, 0x21},
+		{0x1ab, 0x04},
+		{0x1ac, 0x14},
+		{0x1ad, 0x00},
+		{0x1aa, 0x02},
+		{0x1a0, 0x00},
+	};
+#endif
+	for (int i = 0; i < sizeof(cfg_pll_data)/sizeof(reg_value_t); i++) {
+		hdmi_write(priv, cfg_pll_data[i].value, cfg_pll_data[i].reg);
+	}
+	return;
+}
+
+static void inno_hdmi_tx_ctrl(struct sf_hdmi_priv *priv,vic_code_t vic)
+{
+	hdmi_write(priv, 0x06, 0x9f);
+	hdmi_write(priv, 0x82, 0xa0);
+	hdmi_write(priv, 0xd, 0xa2);
+	hdmi_write(priv, 0x0, 0xa3);
+	hdmi_write(priv, 0x0, 0xa4);
+	hdmi_write(priv, 0x8, 0xa5);
+	hdmi_write(priv, 0x70, 0xa6);
+	hdmi_write(priv, vic, 0xa7);  //conifg video format Identification Code
+	hdmi_write(priv, 0x10, 0xc9); //bist mode: 0x00, normal mode: 0x10, phy mode: 0x4
+}
+
+static void inno_hdmi_tx_phy_param_config(struct sf_hdmi_priv *priv,resolution_t type)
+{
+	vic_code_t vic;
+	switch(type) {
+    case RES_1440_480I_60HZ:
+		vic = VIC_1440x480i60;
+		inno_hdmi_config_1440x480i60(priv);
+	    break;
+	case RES_640_480P_60HZ:
+		vic = VIC_640x480p60;
+		inno_hdmi_config_640x480p60(priv);
+		break;
+	case RES_720_480P_60HZ:
+		vic = VIC_720x480p60;
+		inno_hdmi_config_720x480p60(priv);
+		break;
+	case RES_1280_720P_60HZ:
+		vic = VIC_1280x720p60;
+		inno_hdmi_config_1280x720p60(priv);
+		break;
+	case RES_1920_1080P_60HZ:
+		vic = VIC_1920x1080p60;
+		inno_hdmi_config_1920x1080p60(priv);
+		break;
+	case RES_3840_2160P_30HZ:
+		vic = VIC_3840x2160p30;
+		inno_hdmi_config_3840x2160p30(priv);
+		break;
+	case RES_3840_2160P_60HZ:
+		vic = VIC_3840x2160p60;
+		inno_hdmi_config_3840x2160p60(priv);
+		break;
+	}
+	inno_hdmi_tx_ctrl(priv, vic);
+
+    return;
+}
+
+static void inno_hdmi_tx_phy_power_on(struct sf_hdmi_priv *priv)
+{
+	hdmi_write(priv, 0x61, 0x00); //0x61: power 0n, 0x63: power off
+}
+
+static void inno_hdmi_data_sync(struct sf_hdmi_priv *priv)
+{
+	hdmi_write(priv, 0x00, 0xce);
+	hdmi_write(priv, 0x01, 0xce);
+}
+
+void inno_hdmi_tmds_driver_on(struct sf_hdmi_priv *priv)
+{
+	hdmi_write(priv, 0x8f, 0x1b2);
+	mdelay(50);
+}
+
+static int inno_hdmi_enable(struct udevice *dev, int panel_bpp,
 			      const struct display_timing *edid)
 {
+	struct sf_hdmi_priv *priv = dev_get_priv(dev);
+	debug("inno_hdmi_enable on\r\n");
+	inno_hdmi_detect(priv);
+	inno_hdmi_tx_phy_power_down(priv);
+	inno_hdmi_tx_phy_param_config(priv,RES_1920_1080P_60HZ);
+	inno_hdmi_tx_phy_power_on(priv);
+	inno_hdmi_tmds_driver_on(priv);
+	/*data sync*/
+	inno_hdmi_data_sync(priv);
 	return 0;
 }
 
 int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size)
 {
+	//need fix next
  	return 0;
 }
 
-static int rk3399_hdmi_of_to_plat(struct udevice *dev)
+static int inno_hdmi_of_to_plat(struct udevice *dev)
 {
+	struct sf_hdmi_priv *priv = dev_get_priv(dev);
+	int ret;
+	priv->base = dev_remap_addr(dev);
+	if (!priv->base)
+		return -EINVAL;
+	debug("%s----priv->base = %px\n",__func__,priv->base);
+
+	ret = clk_get_by_name(dev, "sysclk", &priv->sys_clk);
+	if (ret) {
+		pr_err("clk_get_by_name(sysclk) failed: %d", ret);
+		return ret;
+	}
+
+	ret = clk_get_by_name(dev, "mclk", &priv->mclk);
+	if (ret) {
+		pr_err("clk_get_by_name(mclk) failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_get_by_name(dev, "bclk", &priv->bclk);
+	if (ret) {
+		pr_err("clk_get_by_name(bclk) failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = reset_get_by_name(dev, "hdmi_tx", &priv->tx_rst);
+	if (ret) {
+		pr_err("failed to get hdmi_tx reset (ret=%d)\n", ret);
+		return ret;
+	}
 	return 0;
 }
 
-static int rk3399_hdmi_probe(struct udevice *dev)
+static int inno_hdmi_probe(struct udevice *dev)
 {
-	return 0;
+	struct sf_hdmi_priv *priv = dev_get_priv(dev);
+	int ret;
+	ret = clk_enable(&priv->sys_clk);
+	if (ret < 0) {
+		pr_err("clk_enable(sys_clk) failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_enable(&priv->mclk);
+	if (ret < 0) {
+		pr_err("clk_enable(mclk) failed: %d\n", ret);
+		goto free_clock_sys_clk;
+	}
+
+	ret = clk_enable(&priv->bclk);
+	if (ret < 0) {
+		pr_err("clk_enable(bclk) failed: %d\n", ret);
+		goto free_clock_mclk_clk;
+	}
+
+	ret = reset_deassert(&priv->tx_rst);
+	if (ret < 0) {
+		pr_err("failed to deassert tx_rst\n");
+		goto free_reset;
+	}
+
+	ret = (hdmi_read(priv, HDMI_STATUS) & m_HOTPLUG) ? 0 : 1; // 0 connected.. 1 disconnected
+	debug("ret = %d\n",ret);
+	return ret;
+
+free_reset:
+	clk_disable(&priv->bclk);
+free_clock_mclk_clk:
+	clk_disable(&priv->mclk);
+free_clock_sys_clk:
+	clk_disable(&priv->sys_clk);
+
+	return ret;
+
 }
 
-static const struct dm_display_ops rk3399_hdmi_ops = {
+static const struct dm_display_ops inno_hdmi_ops = {
 	.read_edid = rk_hdmi_read_edid,
-	.enable = rk3399_hdmi_enable,
+	.enable = inno_hdmi_enable,
 };
 
-static const struct udevice_id rk3399_hdmi_ids[] = {
-	{ .compatible = "rockchip,rk3288-dw-hdmi" },
+static const struct udevice_id inno_hdmi_ids[] = {
+	{ .compatible = "starfive,inno-hdmi" },
 	{ }
 };
 
-U_BOOT_DRIVER(rk3399_hdmi_rockchip) = {
-	.name = "rk3399_hdmi_rockchip",
+U_BOOT_DRIVER(inno_hdmi_starfive) = {
+	.name = "inno_hdmi_starfive",
 	.id = UCLASS_DISPLAY,
-	.of_match = rk3399_hdmi_ids,
-	.ops = &rk3399_hdmi_ops,
-	.of_to_plat = rk3399_hdmi_of_to_plat,
-	.probe = rk3399_hdmi_probe,
-	.priv_auto	= sizeof(struct rk_hdmi_priv),
+	.of_match = inno_hdmi_ids,
+	.ops = &inno_hdmi_ops,
+	.of_to_plat = inno_hdmi_of_to_plat,
+	.probe = inno_hdmi_probe,
+	.priv_auto	= sizeof(struct sf_hdmi_priv),
 };

+ 47 - 60
drivers/video/starfive/sf_hdmi.h

@@ -3,73 +3,60 @@
  * Copyright (c) 2017 Theobroma Systems Design und Consulting GmbH
  */
 
-#ifndef __RK_HDMI_H__
-#define __RK_HDMI_H__
+#ifndef __SF_HDMI_H__
+#define __SF_HDMI_H__
 
-struct rkhdmi_driverdata {
-	/* configuration */
-	u8 i2c_clk_high;
-	u8 i2c_clk_low;
-	const char * const *regulator_names;
-	u32 regulator_names_cnt;
-	/* setters/getters */
-	int (*set_input_vop)(struct udevice *dev);
-	int (*clk_config)(struct udevice *dev);
-};
+#include <clk.h>
+#include <reset.h>
+
+#define HDMI_STATUS				0xc8
+#define m_HOTPLUG				(1 << 7)
+#define m_MASK_INT_HOTPLUG		(1 << 5)
+#define m_INT_HOTPLUG			(1 << 1)
+#define v_MASK_INT_HOTPLUG(n)	((n & 0x1) << 5)
+
+typedef struct
+{
+    /* TODO: add hdmi inno registers define */
+} hdmi_regs_t;
 
-struct rk_hdmi_priv {
+typedef struct register_value {
+	u16 reg;
+	u8 value;
+}reg_value_t;
+
+struct sf_hdmi_priv {
 	struct dw_hdmi hdmi;
 	void *grf;
+	void __iomem *base;
+
+	struct clk  pclk;
+	struct clk  sys_clk;
+	struct clk  mclk;
+	struct clk  bclk;
+	struct clk  phy_clk;
+	struct reset_ctl  tx_rst;
 };
 
-/**
- * rk_hdmi_read_edid() - read the attached HDMI/DVI monitor's EDID
- *
- * N.B.: The buffer should be large enough to hold 2 EDID blocks, as
- *       this function calls dw_hdmi_read_edid, which ignores buf_size
- *       argument and assumes that there's always enough space for 2
- *       EDID blocks.
- *
- * @dev:	device
- * @buf:	output buffer for the EDID
- * @buf_size:	number of bytes in the buffer
- * @return number of bytes read if OK, -ve if something went wrong
- */
-int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size);
+typedef enum {
+	RES_1440_480I_60HZ = 0,
+	RES_640_480P_60HZ,
+	RES_720_480P_60HZ,
+	RES_1280_720P_60HZ,
+	RES_1920_1080P_60HZ,
+	RES_3840_2160P_30HZ,
+	RES_3840_2160P_60HZ,
+}resolution_t;
 
-/**
- * rk_hdmi_probe_regulators() - probe (autoset + enable) regulators
- *
- * Probes a list of regulators by performing autoset and enable
- * operations on them.  The list of regulators is an array of string
- * pointers and any individual regulator-probe may fail without
- * counting as an error.
- *
- * @dev:	device
- * @names:	array of string-pointers to regulator names to probe
- * @cnt:	number of elements in the 'names' array
- */
-void rk_hdmi_probe_regulators(struct udevice *dev,
-			      const char * const *names, int cnt);
-/**
- * rk_hdmi_of_to_plat() - common of_to_plat implementation
- *
- * @dev:	device
- * @return 0 if OK, -ve if something went wrong
- */
-int rk_hdmi_of_to_plat(struct udevice *dev);
+typedef enum {
+	VIC_1440x480i60 = 6,
+	VIC_640x480p60 = 1,
+	VIC_720x480p60 = 2,
+	VIC_1280x720p60 = 4,
+	VIC_1920x1080p60 = 16,
+	VIC_3840x2160p30 = 95,
+	VIC_3840x2160p60 = 97,
+}vic_code_t;
 
-/**
- * rk_hdmi_probe() - common probe implementation
- *
- * Performs the following, common initialisation steps:
- * 1. checks for HPD (i.e. a HDMI monitor being attached)
- * 2. initialises the Designware HDMI core
- * 3. initialises the Designware HDMI PHY
- *
- * @dev:	device
- * @return 0 if OK, -ve if something went wrong
- */
-int rk_hdmi_probe(struct udevice *dev);
 
 #endif

+ 10 - 15
drivers/video/starfive/sf_mipi.c

@@ -1,3 +1,5 @@
+#include <asm/gpio.h>
+#include <asm/io.h>
 #include <common.h>
 #include <clk.h>
 #include <display.h>
@@ -6,23 +8,21 @@
 #include <panel.h>
 #include <regmap.h>
 #include <syscon.h>
-#include <asm/gpio.h>
-#include <asm/io.h>
+
 #include <dm/uclass-internal.h>
 #include <linux/err.h>
 #include <linux/kernel.h>
-#include <video_bridge.h>
+#include <linux/delay.h>
+#include <linux/iopoll.h>
+#include <linux/err.h>
+#include <power/regulator.h>
 
+#include <video_bridge.h>
 #include <dsi_host.h>
 #include <mipi_dsi.h>
 #include <reset.h>
 #include <video.h>
 
-#include <linux/iopoll.h>
-#include <linux/err.h>
-#include <power/regulator.h>
-#include <regmap.h>
-#include <syscon.h>
 #include "sf_mipi.h"
 
 static inline u32 sf_dphy_get_reg(void __iomem * io_addr, u32 shift, u32 mask)
@@ -72,11 +72,6 @@ static void reset(int assert, void __iomem *phy_reg)
 	}
 }
 
-static inline void sys_delay(int cycles)
-{
-    while (cycles--);
-}
-
 int sys_mipi_dsi_set_ppi_txbyte_hs(int enable, void *priv_data)
 {
 	struct mipi_dsi_device *device = priv_data;
@@ -97,7 +92,7 @@ int sys_mipi_dsi_set_ppi_txbyte_hs(int enable, void *priv_data)
 			return ret;
 		}
 	}
-	sys_delay(100);
+	mdelay(100);
 	return 0;
 }
 
@@ -253,7 +248,7 @@ static int dsi_sf_attach(struct udevice *dev)
 
 	ret = uclass_first_device(UCLASS_PANEL, &priv->panel);
 	if (ret) {
-		printf("panel device error %d\n", ret);
+		debug("panel device error %d\n", ret);
 		return ret;
 	}
 	debug("%s,priv->panel->name = %s\n", __func__,priv->panel->name);

+ 111 - 23
drivers/video/starfive/sf_vop.c

@@ -349,6 +349,9 @@ static int sf_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
 	u32 remote_phandle;
 	ofnode remote;
 	const char *compat;
+	struct display_plat *disp_uc_plat;
+	debug("%s(%s, 0x%lx, %s)\n", __func__,
+			  dev_read_name(dev), fbbase, ofnode_get_name(ep_node));
 
 	struct udevice *panel = NULL;
 
@@ -361,6 +364,7 @@ static int sf_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
 		return -EINVAL;
 	remote_vop_id = ofnode_read_u32_default(remote, "reg", -1);
 	uc_priv->bpix = VIDEO_BPP32;
+	debug("remote_vop_id  %d\n", remote_vop_id);
 
 	/*
 	 * The remote-endpoint references into a subnode of the encoder
@@ -388,14 +392,19 @@ static int sf_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
 			      __func__, dev_read_name(dev));
 			return -EINVAL;
 		}
-
+		debug("%s(%s, 0x%lx,remote %s)\n", __func__,
+		  dev_read_name(dev), fbbase, ofnode_get_name(remote));
+		uclass_find_device_by_ofnode(UCLASS_DISPLAY, remote, &disp);
+		if (disp)
+			break;
 		uclass_find_device_by_ofnode(UCLASS_VIDEO_BRIDGE, remote, &disp);
 		if (disp)
 			break;
+
 	};
 	compat = ofnode_get_property(remote, "compatible", NULL);
 	if (!compat) {
-		printf("%s(%s): Failed to find compatible property\n",
+		debug("%s(%s): Failed to find compatible property\n",
 		      __func__, dev_read_name(dev));
 		return -EINVAL;
 	}
@@ -410,24 +419,111 @@ static int sf_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
 	} else if (strstr(compat, "lvds")) {
 		vop_id = VOP_MODE_LVDS;
 	} else {
-		printf("%s(%s): Failed to find vop mode for %s\n",
+		debug("%s(%s): Failed to find vop mode for %s\n",
 		      __func__, dev_read_name(dev), compat);
 		return -EINVAL;
 	}
 
-	ret = device_probe(disp);
-	if (ret) {
-		printf("%s: device '%s' display won't probe (ret=%d)\n",
-		      __func__, dev->name, ret);
-		return ret;
+	debug("vop_id  %d,compat = %s\n", vop_id,compat);
+	if(vop_id == VOP_MODE_HDMI)
+	{
+		disp_uc_plat = dev_get_uclass_plat(disp);
+		debug("Found device '%s', disp_uc_priv=%p\n", disp->name, disp_uc_plat);
+
+
+		disp_uc_plat->source_id = remote_vop_id;
+		disp_uc_plat->src_dev = dev;
+
+		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_enable(disp, 1 << VIDEO_BPP32, &timing);
+		if (ret) {
+			debug("%s: Failed to read timings\n", __func__);
+			return ret;
+		}
+		int err = clk_set_parent(&priv->dc_pix0, &priv->dc_pix_src);
+		if (err) {
+			debug("failed to set %s clock as %s's parent\n",
+				priv->dc_pix_src.dev->name, priv->dc_pix0.dev->name);
+			return err;
+		}
+
+		ulong new_rate = clk_set_rate(&priv->dc_pix_src, 148500000);
+		debug("new_rate  %ld\n", new_rate);
+
+		dc_hw_init(dev);
+
+		uc_priv->xsize = 1920;
+		uc_priv->ysize = 1080;
+
+		writel(0xc0001fff, priv->regs_hi+0x00000014);
+		writel(0x00002000, priv->regs_hi+0x00001cc0);
+		//writel(uc_plat->base+0x1fa400, priv->regs_hi+0x00001530);
+		writel(0x00000000, priv->regs_hi+0x00001800);
+		writel(0x00000000, priv->regs_hi+0x000024d8);
+		writel(0x021c0780, priv->regs_hi+0x000024e0);
+		writel(0x021c0780, priv->regs_hi+0x00001810);
+		writel(uc_plat->base, priv->regs_hi+0x00001400);
+		writel(0x00001e00, priv->regs_hi+0x00001408);
+		writel(0x00000f61, priv->regs_hi+0x00001ce8);
+		writel(0x00002042, priv->regs_hi+0x00002510);
+		writel(0x808a3156, priv->regs_hi+0x00002508);
+		writel(0x8008e1b2, priv->regs_hi+0x00002500);
+		writel(0x18000000, priv->regs_hi+0x00001518);
+		writel(0x00003000, priv->regs_hi+0x00001cc0);
+		writel(0x00060000, priv->regs_hi+0x00001540);
+		writel(0x00000001, priv->regs_hi+0x00002540);
+		writel(0x80060000, priv->regs_hi+0x00001540);
+		writel(0x00060000, priv->regs_hi+0x00001544);
+		writel(0x00000002, priv->regs_hi+0x00002544);
+		writel(0x80060000, priv->regs_hi+0x00001544);
+		writel(0x00060000, priv->regs_hi+0x00001548);
+		writel(0x0000000c, priv->regs_hi+0x00002548);
+		writel(0x80060000, priv->regs_hi+0x00001548);
+		writel(0x00060000, priv->regs_hi+0x0000154c);
+		writel(0x0000000d, priv->regs_hi+0x0000254c);
+		writel(0x80060000, priv->regs_hi+0x0000154c);
+		writel(0x00000001, priv->regs_hi+0x00002518);
+		writel(0x00000000, priv->regs_hi+0x00001a28);
+		writel(0x08980780, priv->regs_hi+0x00001430);
+		writel(0x440207d8, priv->regs_hi+0x00001438);
+		writel(0x04650438, priv->regs_hi+0x00001440);
+		writel(0x4220843c, priv->regs_hi+0x00001448);
+		writel(0x00000000, priv->regs_hi+0x000014b0);
+		writel(0x000000d2, priv->regs_hi+0x00001cd0);
+		writel(0x00000005, priv->regs_hi+0x000014b8);
+		writel(0x00000052, priv->regs_hi+0x000014d0);
+		writel(0xdeadbeef, priv->regs_hi+0x00001528);
+		writel(0x00001111, priv->regs_hi+0x00001418);
+		writel(0x00000000, priv->regs_hi+0x00001410);
+		writel(0x00000000, priv->regs_hi+0x00002518);
+		writel(0x00200024, priv->regs_hi+0x00001468);
+		writel(0x00000000, priv->regs_hi+0x00001484);
+		writel(0x00200024, priv->regs_hi+0x00001468);
+		writel(0x00000c24, priv->regs_hi+0x000024e8);
+		writel(0x00000000, priv->regs_hi+0x000024fc);
+		writel(0x00000c24, priv->regs_hi+0x000024e8);
+		writel(0x00000001, priv->regs_hi+0x00001ccc);
+		return 0;
 	}
-	debug("%s,vop_id = %d\n", __func__,vop_id);
 
 	if(vop_id == VOP_MODE_MIPI)
 	{
+		ret = device_probe(disp);
+		if (ret) {
+			debug("%s: device '%s' display won't probe (ret=%d)\n",
+				  __func__, dev->name, ret);
+			return ret;
+		}
+
 		ret = video_bridge_attach(disp);
 		if (ret) {
-			printf("fail to attach bridge\n");
+			debug("fail to attach bridge\n");
 			return ret;
 		}
 
@@ -440,7 +536,7 @@ static int sf_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
 		ret = uclass_first_device_err(UCLASS_PANEL, &panel);
 		if (ret) {
 			if (ret != -ENODEV)
-				printf("panel device error %d\n", ret);
+				debug("panel device error %d\n", ret);
 			return ret;
 		}
 
@@ -449,14 +545,14 @@ static int sf_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
 			ret = ofnode_decode_display_timing(dev_ofnode(panel),
 							   0, &timing);
 			if (ret) {
-				printf("decode display timing error %d\n", ret);
+				debug("decode display timing error %d\n", ret);
 				return ret;
 			}
 		}
 
 		int err = clk_set_parent(&priv->dc_pix0, &priv->dc_pix_src);
 		if (err) {
-			printf("failed to set %s clock as %s's parent\n",
+			debug("failed to set %s clock as %s's parent\n",
 				priv->dc_pix_src.dev->name, priv->dc_pix0.dev->name);
 			return err;
 		}
@@ -521,6 +617,7 @@ static int sf_display_init(struct udevice *dev, ulong fbbase, ofnode ep_node)
 		writel(0x00000000, priv->regs_hi+0x000024fc); //csr_reg
 		writel(0x00011b25, priv->regs_hi+0x000024e8); //csr_reg
 		writel(0x00000001, priv->regs_hi+0x00001ccc); //csr_reg
+		return 0;
 	}
 
 	return 0;
@@ -547,21 +644,12 @@ static int sf_vop_probe(struct udevice *dev)
 
 	vout_probe_resources_jh7110(dev);
 
-	/*
-	 * Try all the ports until we find one that works. In practice this
-	 * tries EDP first if available, then HDMI.
-	 *
-	 * Note that rockchip_vop_set_clk() always uses NPLL as the source
-	 * clock so it is currently not possible to use more than one display
-	 * device simultaneously.
-	 */
 	port = dev_read_subnode(dev, "port");
 	if (!ofnode_valid(port)) {
 		debug("%s(%s): 'port' subnode not found\n",
 		      __func__, dev_read_name(dev));
 		return -EINVAL;
 	}
-
 	for (node = ofnode_first_subnode(port);
 	     ofnode_valid(node);
 	     node = dev_read_next_subnode(node)) {
@@ -601,7 +689,7 @@ int sf_vop_bind(struct udevice *dev)
 
 	plat->size = 4 * (CONFIG_VIDEO_STARFIVE_MAX_XRES *
 			  CONFIG_VIDEO_STARFIVE_MAX_YRES);
-	printf("%s,%d,plat->size = %d\n",__func__,__LINE__,plat->size);
+	debug("%s,%d,plat->size = %d\n",__func__,__LINE__,plat->size);
 
 	return 0;
 }