author: andy.hu <andy.hu@starfivetech.com> 2023-03-09 09:19:55 +0000
committer: andy.hu <andy.hu@starfivetech.com> 2023-03-09 09:19:55 +0000
commit: d4dedcadbc2e80be5b91556b7b1f14cd28c9d0e1
parent: f7261333cb0e3e0c55e025b3069d655d745ef878
Commit Summary:
Diffstat:
7 files changed, 660 insertions, 161 deletions
diff --git a/arch/riscv/dts/jh7110.dtsi b/arch/riscv/dts/jh7110.dtsi
index 9e5b0576f9..cf9a1eebb2 100644
--- a/arch/riscv/dts/jh7110.dtsi
+++ b/arch/riscv/dts/jh7110.dtsi
@@ -1335,38 +1335,20 @@
remote-endpoint = <&hdmi_in_vopb>;
};
- vopb_out_lvds: endpoint@2 {
- reg = <2>;
- remote-endpoint = <&lvds_in_vopb>;
- };
-
- vopb_out_edp: endpoint@3 {
- reg = <3>;
- remote-endpoint = <&edp_in_vopb>;
- };
- };
- };
-
- edp: edp@29600000 {
- compatible = "rockchip,rk3288-edp";
- reg = <0x0 0x29600000 0x0 0x4000>;
- status = "okay";
- ports {
- edp_in: port {
- #address-cells = <1>;
- #size-cells = <0>;
- edp_in_vopb: endpoint@0 {
- reg = <0>;
- remote-endpoint = <&vopb_out_edp>;
- };
- };
};
};
hdmi: hdmi@29590000 {
- compatible = "rockchip,rk3288-dw-hdmi";
+ compatible = "starfive,inno-hdmi";
reg = <0x0 0x29590000 0x0 0x4000>;
status = "okay";
+ clocks = <&clkvout JH7110_U0_HDMI_TX_CLK_SYS>,
+ <&clkvout JH7110_U0_HDMI_TX_CLK_MCLK>,
+ <&clkvout JH7110_U0_HDMI_TX_CLK_BCLK>;
+ clock-names = "sysclk", "mclk","bclk";
+ resets = <&rstgen RSTN_U0_HDMI_TX_HDMI>;
+ reset-names = "hdmi_tx";
+
ports {
hdmi_in: port {
#address-cells = <1>;
@@ -1379,25 +1361,6 @@
};
};
- lvds: lvds@ff96c000 {
- compatible = "rockchip,rk3288-lvds";
- reg = <0x0 0xff96c000 0x0 0x4000>;
- status = "okay";
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
- lvds_in: port@0 {
- reg = <0>;
- #address-cells = <1>;
- #size-cells = <0>;
- lvds_in_vopb: endpoint@0 {
- reg = <0>;
- remote-endpoint = <&vopb_out_lvds>;
- };
- };
- };
- };
-
mipi_dsi0: mipi@295d0000 {
compatible = "starfive,sf_mipi_dsi";
reg = <0x0 0x295d0000 0x0 0x10000>,
diff --git a/arch/riscv/dts/starfive_evb.dts b/arch/riscv/dts/starfive_evb.dts
index dcccb48a39..6f865f7094 100644
--- a/arch/riscv/dts/starfive_evb.dts
+++ b/arch/riscv/dts/starfive_evb.dts
@@ -340,7 +340,6 @@
&mipi_dsi0 {
-
status = "okay";
rockchip,panel = <&rm68200_panel>;
data-lanes-num = <1>;
@@ -365,6 +364,11 @@
};
+&hdmi{
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_pins>;
+ status = "okay";
+};
&i2c2 {
clock-frequency = <100000>;
diff --git a/drivers/video/raydium-rm68200-starfive.c b/drivers/video/raydium-rm68200-starfive.c
index d455e5946d..c4234d58f2 100644
--- a/drivers/video/raydium-rm68200-starfive.c
+++ b/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;
}
diff --git a/drivers/video/starfive/sf_hdmi.c b/drivers/video/starfive/sf_hdmi.c
index 319080114f..80f5b11989 100644
--- a/drivers/video/starfive/sf_hdmi.c
+++ b/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),
};
diff --git a/drivers/video/starfive/sf_hdmi.h b/drivers/video/starfive/sf_hdmi.h
index 859a0b9ff3..96177e1b0d 100644
--- a/drivers/video/starfive/sf_hdmi.h
+++ b/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
diff --git a/drivers/video/starfive/sf_mipi.c b/drivers/video/starfive/sf_mipi.c
index 8c2bcea845..4521f7c869 100644
--- a/drivers/video/starfive/sf_mipi.c
+++ b/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);
diff --git a/drivers/video/starfive/sf_vop.c b/drivers/video/starfive/sf_vop.c
index b2ad6e4c59..8b62851dc2 100644
--- a/drivers/video/starfive/sf_vop.c
+++ b/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;
}