From 04dd17822334871b23ea2862f7798fb0e0007777 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Sat, 11 May 2024 08:53:19 +0000
Subject: [PATCH] change otg to host mode
---
u-boot/drivers/video/drm/dw_hdmi.c | 186 ++++++++++++++++++++++++++++++++++++++--------
1 files changed, 154 insertions(+), 32 deletions(-)
diff --git a/u-boot/drivers/video/drm/dw_hdmi.c b/u-boot/drivers/video/drm/dw_hdmi.c
index f993a21..a30e4d5 100644
--- a/u-boot/drivers/video/drm/dw_hdmi.c
+++ b/u-boot/drivers/video/drm/dw_hdmi.c
@@ -7,6 +7,7 @@
#include <common.h>
#include <malloc.h>
#include <syscon.h>
+#include <asm/gpio.h>
#include <asm/arch-rockchip/clock.h>
#include <asm/arch/vendor.h>
#include <edid.h>
@@ -27,6 +28,7 @@
#define HDCP_PRIVATE_KEY_SIZE 280
#define HDCP_KEY_SHA_SIZE 20
#define HDMI_HDCP1X_ID 5
+#define HDMI_EDID_BLOCK_LEN 128
/*
* Unless otherwise noted, entries in this table are 100% optimization.
* Values can be obtained from hdmi_compute_n() but that function is
@@ -181,6 +183,7 @@
bool sink_has_audio;
void *regs;
void *grf;
+ void *gpio_base;
struct dw_hdmi_i2c *i2c;
struct {
@@ -203,6 +206,8 @@
bool hdcp1x_enable;
bool output_bus_format_rgb;
+
+ struct gpio_desc hpd_gpiod;
};
static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset)
@@ -409,6 +414,7 @@
{
struct dw_hdmi_i2c *i2c = hdmi->i2c;
int interrupt = 0, i = 20;
+ bool read_edid = false;
if (!i2c->is_regaddr) {
printf("set read register address to 0\n");
@@ -416,14 +422,36 @@
i2c->is_regaddr = true;
}
- while (length--) {
- hdmi_writeb(hdmi, i2c->slave_reg++, HDMI_I2CM_ADDRESS);
- if (i2c->is_segment)
- hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ_EXT,
- HDMI_I2CM_OPERATION);
- else
- hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ,
- HDMI_I2CM_OPERATION);
+ /* edid reads are in 128 bytes. scdc reads are in 1 byte */
+ if (length == HDMI_EDID_BLOCK_LEN)
+ read_edid = true;
+
+ while (length > 0) {
+ hdmi_writeb(hdmi, i2c->slave_reg, HDMI_I2CM_ADDRESS);
+
+ if (read_edid) {
+ i2c->slave_reg += 8;
+ length -= 8;
+ } else {
+ i2c->slave_reg++;
+ length--;
+ }
+
+ if (i2c->is_segment) {
+ if (read_edid)
+ hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ8_EXT,
+ HDMI_I2CM_OPERATION);
+ else
+ hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ_EXT,
+ HDMI_I2CM_OPERATION);
+ } else {
+ if (read_edid)
+ hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ8,
+ HDMI_I2CM_OPERATION);
+ else
+ hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ,
+ HDMI_I2CM_OPERATION);
+ }
while (i--) {
udelay(1000);
@@ -439,6 +467,10 @@
if (!interrupt) {
printf("[%s] i2c read reg[0x%02x] no interrupt\n",
__func__, i2c->slave_reg);
+ hdmi_writeb(hdmi, 0, HDMI_I2CM_SOFTRSTZ);
+ hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_BUS_CLEAR,
+ HDMI_I2CM_OPERATION);
+ udelay(1000);
return -EAGAIN;
}
@@ -446,11 +478,19 @@
if (interrupt & HDMI_IH_I2CM_STAT0_ERROR) {
printf("[%s] read reg[0x%02x] data error:0x%02x\n",
__func__, i2c->slave_reg, interrupt);
+ hdmi_writeb(hdmi, 0, HDMI_I2CM_SOFTRSTZ);
+ hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_BUS_CLEAR,
+ HDMI_I2CM_OPERATION);
+ udelay(1000);
return -EIO;
}
i = 20;
- *buf++ = hdmi_readb(hdmi, HDMI_I2CM_DATAI);
+ if (read_edid)
+ for (i = 0; i < 8; i++)
+ *buf++ = hdmi_readb(hdmi, HDMI_I2CM_READ_BUFF0 + i);
+ else
+ *buf++ = hdmi_readb(hdmi, HDMI_I2CM_DATAI);
}
i2c->is_segment = false;
@@ -490,8 +530,22 @@
break;
}
+ if (!interrupt) {
+ printf("[%s] i2c write reg[0x%02x] no interrupt\n",
+ __func__, i2c->slave_reg);
+ hdmi_writeb(hdmi, 0, HDMI_I2CM_SOFTRSTZ);
+ hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_BUS_CLEAR,
+ HDMI_I2CM_OPERATION);
+ udelay(1000);
+ return -EAGAIN;
+ }
+
if ((interrupt & m_I2CM_ERROR) || (i == -1)) {
printf("[%s] write data error\n", __func__);
+ hdmi_writeb(hdmi, 0, HDMI_I2CM_SOFTRSTZ);
+ hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_BUS_CLEAR,
+ HDMI_I2CM_OPERATION);
+ udelay(1000);
return -EIO;
} else if (interrupt & m_I2CM_DONE) {
printf("[%s] write offset %02x success\n",
@@ -959,6 +1013,7 @@
* but it has a vedor phy.
*/
if (phy_type == DW_HDMI_PHY_VENDOR_PHY ||
+ hdmi->dev_type == RK3528_HDMI ||
hdmi->dev_type == RK3328_HDMI ||
hdmi->dev_type == RK3228_HDMI) {
/* Vendor PHYs require support from the glue layer. */
@@ -1042,14 +1097,11 @@
vmode->mpixelclock, vmode->mtmdsclock);
/* Set up HDMI_FC_INVIDCONF
- * fc_invidconf.HDCP_keepout must be set (1'b1)
- * when activate the scrambler feature.
+ * Some display equipments require that the interval
+ * between Video Data and Data island must be at least 58 pixels,
+ * and fc_invidconf.HDCP_keepout set (1'b1) can meet the requirement.
*/
- inv_val = (vmode->mtmdsclock > 340000000 ||
- (hdmi_info->scdc.scrambling.low_rates &&
- hdmi->scramble_low_rates) ?
- HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
- HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
+ inv_val = HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE;
inv_val |= mode->flags & DRM_MODE_FLAG_PVSYNC ?
HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
@@ -1418,13 +1470,8 @@
HDMI_VP_CONF_PR_EN_MASK |
HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
- if ((color_depth == 5 && hdmi->previous_mode.htotal % 4) ||
- (color_depth == 6 && hdmi->previous_mode.htotal % 2))
- hdmi_modb(hdmi, 0, HDMI_VP_STUFF_IDEFAULT_PHASE_MASK,
- HDMI_VP_STUFF);
- else
- hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
- HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);
+ hdmi_modb(hdmi, 0, HDMI_VP_STUFF_IDEFAULT_PHASE_MASK,
+ HDMI_VP_STUFF);
hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
@@ -1887,6 +1934,7 @@
hdmi->sample_rate);
}
+#ifndef CONFIG_SPL_BUILD
static int dw_hdmi_hdcp_load_key(struct dw_hdmi *hdmi)
{
int i, j, ret, val;
@@ -1952,6 +2000,7 @@
free(hdcp_keys);
return 0;
}
+#endif
static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi,
const struct drm_display_mode *mode)
@@ -1981,8 +2030,10 @@
hdmi_modb(hdmi, hdmi_dvi, HDMI_A_HDCPCFG0_HDMIDVI_MASK,
HDMI_A_HDCPCFG0);
+#ifndef CONFIG_SPL_BUILD
if (!(hdmi_readb(hdmi, HDMI_HDCPREG_RMSTS) & 0x3f))
dw_hdmi_hdcp_load_key(hdmi);
+#endif
hdmi_modb(hdmi, HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE,
HDMI_FC_INVIDCONF_HDCP_KEEPOUT_MASK,
@@ -2269,13 +2320,18 @@
{
struct connector_state *conn_state = &state->conn_state;
const struct dw_hdmi_plat_data *pdata =
+#ifdef CONFIG_SPL_BUILD
+ (const struct dw_hdmi_plat_data *)conn->data;
+#else
(const struct dw_hdmi_plat_data *)dev_get_driver_data(conn->dev);
+ ofnode hdmi_node = conn->dev->node;
+ struct device_node *ddc_node;
+ int ret;
+#endif
struct crtc_state *crtc_state = &state->crtc_state;
struct dw_hdmi *hdmi;
struct drm_display_mode *mode_buf;
- ofnode hdmi_node = conn->dev->node;
u32 val;
- struct device_node *ddc_node;
hdmi = malloc(sizeof(struct dw_hdmi));
if (!hdmi)
@@ -2285,13 +2341,28 @@
mode_buf = malloc(MODE_LEN * sizeof(struct drm_display_mode));
if (!mode_buf)
return -ENOMEM;
+
+#ifdef CONFIG_SPL_BUILD
+ hdmi->id = 0;
+ hdmi->regs = (void *)RK3528_HDMI_BASE;
+ hdmi->io_width = 4;
+ hdmi->scramble_low_rates = false;
+ hdmi->hdcp1x_enable = false;
+ hdmi->output_bus_format_rgb = false;
+ conn_state->type = DRM_MODE_CONNECTOR_HDMIA;
+#else
hdmi->id = of_alias_get_id(ofnode_to_np(hdmi_node), "hdmi");
if (hdmi->id < 0)
hdmi->id = 0;
- conn_state->disp_info = rockchip_get_disp_info(conn_state->type, hdmi->id);
+ conn_state->disp_info = rockchip_get_disp_info(conn_state->type, hdmi->id);
+#endif
memset(mode_buf, 0, MODE_LEN * sizeof(struct drm_display_mode));
+ hdmi->dev_type = pdata->dev_type;
+ hdmi->plat_data = pdata;
+
+#ifndef CONFIG_SPL_BUILD
hdmi->regs = dev_read_addr_ptr(conn->dev);
hdmi->io_width = ofnode_read_s32_default(hdmi_node, "reg-io-width", -1);
@@ -2309,6 +2380,24 @@
else
hdmi->output_bus_format_rgb = false;
+ ret = dev_read_size(conn->dev, "rockchip,phy-table");
+ if (ret > 0 && hdmi->plat_data->phy_config) {
+ u32 phy_config[ret / 4];
+ int i;
+
+ dev_read_u32_array(conn->dev, "rockchip,phy-table", phy_config, ret / 4);
+
+ for (i = 0; i < ret / 16; i++) {
+ if (phy_config[i * 4] != 0)
+ hdmi->plat_data->phy_config[i].mpixelclock = (u64)phy_config[i * 4];
+ else
+ hdmi->plat_data->phy_config[i].mpixelclock = ~0UL;
+ hdmi->plat_data->phy_config[i].sym_ctr = (u16)phy_config[i * 4 + 1];
+ hdmi->plat_data->phy_config[i].term = (u16)phy_config[i * 4 + 2];
+ hdmi->plat_data->phy_config[i].vlev_ctr = (u16)phy_config[i * 4 + 3];
+ }
+ }
+
ddc_node = of_parse_phandle(ofnode_to_np(hdmi_node), "ddc-i2c-bus", 0);
if (ddc_node) {
uclass_get_device_by_ofnode(UCLASS_I2C, np_to_ofnode(ddc_node),
@@ -2316,6 +2405,7 @@
if (hdmi->adap.i2c_bus)
hdmi->adap.ops = i2c_get_ops(hdmi->adap.i2c_bus);
}
+#endif
hdmi->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
if (hdmi->grf <= 0) {
@@ -2323,6 +2413,20 @@
__func__, hdmi->grf);
return -ENXIO;
}
+
+#ifdef CONFIG_SPL_BUILD
+ hdmi->gpio_base = (void *)RK3528_GPIO_BASE;
+#else
+ ret = gpio_request_by_name(conn->dev, "hpd-gpios", 0,
+ &hdmi->hpd_gpiod, GPIOD_IS_IN);
+ if (ret && ret != -ENOENT) {
+ printf("%s: Cannot get HPD GPIO: %d\n", __func__, ret);
+ return ret;
+ }
+ hdmi->gpio_base = (void *)dev_read_addr_index(conn->dev, 1);
+#endif
+ if (!hdmi->gpio_base)
+ return -ENODEV;
dw_hdmi_set_reg_wr(hdmi);
@@ -2345,24 +2449,28 @@
* Read high and low time from device tree. If not available use
* the default timing scl clock rate is about 99.6KHz.
*/
+#ifdef CONFIG_SPL_BUILD
+ hdmi->i2c->scl_high_ns = 9625;
+ hdmi->i2c->scl_low_ns = 10000;
+#else
hdmi->i2c->scl_high_ns =
ofnode_read_s32_default(hdmi_node,
"ddc-i2c-scl-high-time-ns", 4708);
hdmi->i2c->scl_low_ns =
ofnode_read_s32_default(hdmi_node,
"ddc-i2c-scl-low-time-ns", 4916);
+#endif
dw_hdmi_i2c_init(hdmi);
conn_state->output_if |= VOP_OUTPUT_IF_HDMI0;
conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
- hdmi->dev_type = pdata->dev_type;
- hdmi->plat_data = pdata;
hdmi->edid_data.mode_buf = mode_buf;
hdmi->sample_rate = 48000;
conn->data = hdmi;
- dw_hdmi_set_iomux(hdmi->grf, hdmi->dev_type);
+ dw_hdmi_set_iomux(hdmi->grf, hdmi->gpio_base,
+ &hdmi->hpd_gpiod, hdmi->dev_type);
dw_hdmi_detect_phy(hdmi);
dw_hdmi_dev_init(hdmi);
@@ -2413,7 +2521,7 @@
int rockchip_dw_hdmi_get_timing(struct rockchip_connector *conn, struct display_state *state)
{
- int ret, i;
+ int ret, i, vic;
struct connector_state *conn_state = &state->conn_state;
struct drm_display_mode *mode = &conn_state->mode;
struct dw_hdmi *hdmi = conn->data;
@@ -2439,9 +2547,13 @@
hdmi->sink_has_audio = true;
do_cea_modes(&hdmi->edid_data, def_modes_vic,
sizeof(def_modes_vic));
+ hdmi->edid_data.mode_buf[0].type |= DRM_MODE_TYPE_PREFERRED;
hdmi->edid_data.preferred_mode = &hdmi->edid_data.mode_buf[0];
printf("failed to get edid\n");
}
+#ifdef CONFIG_SPL_BUILD
+ conn_state->disp_info = rockchip_get_disp_info(conn_state->type, hdmi->id);
+#endif
drm_rk_filter_whitelist(&hdmi->edid_data);
if (hdmi->phy.ops->mode_valid)
hdmi->phy.ops->mode_valid(conn, hdmi, state);
@@ -2452,9 +2564,20 @@
return -EINVAL;
}
- for (i = 0; i < hdmi->edid_data.modes; i++)
+ for (i = 0; i < hdmi->edid_data.modes; i++) {
hdmi->edid_data.mode_buf[i].vrefresh =
drm_mode_vrefresh(&hdmi->edid_data.mode_buf[i]);
+
+ vic = drm_match_cea_mode(&hdmi->edid_data.mode_buf[i]);
+ if (hdmi->edid_data.mode_buf[i].picture_aspect_ratio == HDMI_PICTURE_ASPECT_NONE) {
+ if (vic >= 93 && vic <= 95)
+ hdmi->edid_data.mode_buf[i].picture_aspect_ratio =
+ HDMI_PICTURE_ASPECT_16_9;
+ else if (vic == 98)
+ hdmi->edid_data.mode_buf[i].picture_aspect_ratio =
+ HDMI_PICTURE_ASPECT_256_135;
+ }
+ }
drm_mode_sort(&hdmi->edid_data);
drm_rk_selete_output(&hdmi->edid_data, conn_state, &bus_format,
@@ -2463,7 +2586,6 @@
*mode = *hdmi->edid_data.preferred_mode;
hdmi->vic = drm_match_cea_mode(mode);
- printf("mode:%dx%d\n", mode->hdisplay, mode->vdisplay);
if (state->force_output)
bus_format = state->force_bus_format;
conn_state->bus_format = bus_format;
--
Gitblit v1.6.2