From ee930fffee469d076998274a2ca55e13dc1efb67 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 08:50:54 +0000 Subject: [PATCH] enable tun/tap/iptables --- 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