diff options
author | Álvaro Fernández Rojas <noltari@gmail.com> | 2021-02-18 18:04:33 +0100 |
---|---|---|
committer | Álvaro Fernández Rojas <noltari@gmail.com> | 2021-02-18 23:42:32 +0100 |
commit | f07e572f6447465d8938679533d604e402b0f066 (patch) | |
tree | cb333bd2a67e59e7c07659514850a0fd55fc825e /target/linux/bcm27xx/patches-5.4/950-0589-drm-vc4-hdmi-Support-the-BCM2711-HDMI-controllers.patch | |
parent | 5d3a6fd970619dfc55f8259035c3027d7613a2a6 (diff) | |
download | upstream-f07e572f6447465d8938679533d604e402b0f066.tar.gz upstream-f07e572f6447465d8938679533d604e402b0f066.tar.bz2 upstream-f07e572f6447465d8938679533d604e402b0f066.zip |
bcm27xx: import latest patches from the RPi foundation
bcm2708: boot tested on RPi B+ v1.2
bcm2709: boot tested on RPi 3B v1.2 and RPi 4B v1.1 4G
bcm2710: boot tested on RPi 3B v1.2
bcm2711: boot tested on RPi 4B v1.1 4G
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
Diffstat (limited to 'target/linux/bcm27xx/patches-5.4/950-0589-drm-vc4-hdmi-Support-the-BCM2711-HDMI-controllers.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-5.4/950-0589-drm-vc4-hdmi-Support-the-BCM2711-HDMI-controllers.patch | 1131 |
1 files changed, 1131 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.4/950-0589-drm-vc4-hdmi-Support-the-BCM2711-HDMI-controllers.patch b/target/linux/bcm27xx/patches-5.4/950-0589-drm-vc4-hdmi-Support-the-BCM2711-HDMI-controllers.patch new file mode 100644 index 0000000000..8a2772299a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0589-drm-vc4-hdmi-Support-the-BCM2711-HDMI-controllers.patch @@ -0,0 +1,1131 @@ +From d0931317c51f14bf65af65e7c3f2df6bb26d7c97 Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime@cerno.tech> +Date: Tue, 17 Dec 2019 11:48:37 +0100 +Subject: [PATCH] drm/vc4: hdmi: Support the BCM2711 HDMI controllers + +Now that the driver is ready for it, let's bring in the HDMI controllers +variants for the BCM2711. + +Signed-off-by: Maxime Ripard <maxime@cerno.tech> +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 254 +++++++++++++++ + drivers/gpu/drm/vc4/vc4_hdmi.h | 35 +++ + drivers/gpu/drm/vc4/vc4_hdmi_phy.c | 469 ++++++++++++++++++++++++++++ + drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 201 ++++++++++++ + 4 files changed, 959 insertions(+) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -42,6 +42,7 @@ + #include <linux/of_platform.h> + #include <linux/pm_runtime.h> + #include <linux/rational.h> ++#include <linux/reset.h> + #include <sound/dmaengine_pcm.h> + #include <sound/pcm_drm_eld.h> + #include <sound/pcm_params.h> +@@ -52,6 +53,31 @@ + #include "vc4_hdmi_regs.h" + #include "vc4_regs.h" + ++#define VC5_HDMI_HORZA_HFP_SHIFT 16 ++#define VC5_HDMI_HORZA_HFP_MASK VC4_MASK(28, 16) ++#define VC5_HDMI_HORZA_VPOS BIT(15) ++#define VC5_HDMI_HORZA_HPOS BIT(14) ++#define VC5_HDMI_HORZA_HAP_SHIFT 0 ++#define VC5_HDMI_HORZA_HAP_MASK VC4_MASK(13, 0) ++ ++#define VC5_HDMI_HORZB_HBP_SHIFT 16 ++#define VC5_HDMI_HORZB_HBP_MASK VC4_MASK(26, 16) ++#define VC5_HDMI_HORZB_HSP_SHIFT 0 ++#define VC5_HDMI_HORZB_HSP_MASK VC4_MASK(10, 0) ++ ++#define VC5_HDMI_VERTA_VSP_SHIFT 24 ++#define VC5_HDMI_VERTA_VSP_MASK VC4_MASK(28, 24) ++#define VC5_HDMI_VERTA_VFP_SHIFT 16 ++#define VC5_HDMI_VERTA_VFP_MASK VC4_MASK(22, 16) ++#define VC5_HDMI_VERTA_VAL_SHIFT 0 ++#define VC5_HDMI_VERTA_VAL_MASK VC4_MASK(12, 0) ++ ++#define VC5_HDMI_VERTB_VSPO_SHIFT 16 ++#define VC5_HDMI_VERTB_VSPO_MASK VC4_MASK(29, 16) ++ ++# define VC4_HD_M_SW_RST BIT(2) ++# define VC4_HD_M_ENABLE BIT(0) ++ + #define CEC_CLOCK_FREQ 40000 + + static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) +@@ -75,6 +101,13 @@ static void vc4_hdmi_reset(struct vc4_hd + HDMI_WRITE(HDMI_SW_RESET_CONTROL, 0); + } + ++static void vc5_hdmi_reset(struct vc4_hdmi *vc4_hdmi) ++{ ++ reset_control_reset(vc4_hdmi->reset); ++ ++ HDMI_WRITE(HDMI_DVP_CTL, 0); ++} ++ + static enum drm_connector_status + vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) + { +@@ -371,6 +404,45 @@ static void vc4_hdmi_csc_setup(struct vc + HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); + } + ++static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) ++{ ++ u32 csc_ctl; ++ ++ csc_ctl = 0x07; /* RGB_CONVERT_MODE = custom matrix, || USE_RGB_TO_YCBCR */ ++ ++ if (enable) { ++ /* CEA VICs other than #1 requre limited range RGB ++ * output unless overridden by an AVI infoframe. ++ * Apply a colorspace conversion to squash 0-255 down ++ * to 16-235. The matrix here is: ++ * ++ * [ 0.8594 0 0 16] ++ * [ 0 0.8594 0 16] ++ * [ 0 0 0.8594 16] ++ * [ 0 0 0 1] ++ * Matrix is signed 2p13 fixed point, with signed 9p6 offsets ++ */ ++ HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x1b80); ++ HDMI_WRITE(HDMI_CSC_14_13, (0x0400 << 16) | 0x0000); ++ HDMI_WRITE(HDMI_CSC_22_21, (0x1b80 << 16) | 0x0000); ++ HDMI_WRITE(HDMI_CSC_24_23, (0x0400 << 16) | 0x0000); ++ HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000); ++ HDMI_WRITE(HDMI_CSC_34_33, (0x0400 << 16) | 0x1b80); ++ } else { ++ /* Still use the matrix for full range, but make it unity. ++ * Matrix is signed 2p13 fixed point, with signed 9p6 offsets ++ */ ++ HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x2000); ++ HDMI_WRITE(HDMI_CSC_14_13, (0x0000 << 16) | 0x0000); ++ HDMI_WRITE(HDMI_CSC_22_21, (0x2000 << 16) | 0x0000); ++ HDMI_WRITE(HDMI_CSC_24_23, (0x0000 << 16) | 0x0000); ++ HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000); ++ HDMI_WRITE(HDMI_CSC_34_33, (0x0000 << 16) | 0x2000); ++ } ++ ++ HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); ++} ++ + static void vc4_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, + struct drm_display_mode *mode) + { +@@ -420,6 +492,58 @@ static void vc4_hdmi_set_timings(struct + (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); + } + ++static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, ++ struct drm_display_mode *mode) ++{ ++ bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC; ++ bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC; ++ bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE; ++ u32 pixel_rep = (mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1; ++ u32 verta = (VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start, ++ VC5_HDMI_VERTA_VSP) | ++ VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay, ++ VC5_HDMI_VERTA_VFP) | ++ VC4_SET_FIELD(mode->crtc_vdisplay, VC5_HDMI_VERTA_VAL)); ++ u32 vertb = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) | ++ VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end, ++ VC4_HDMI_VERTB_VBP)); ++ u32 vertb_even = (VC4_SET_FIELD(0, VC5_HDMI_VERTB_VSPO) | ++ VC4_SET_FIELD(mode->crtc_vtotal - ++ mode->crtc_vsync_end - ++ interlaced, ++ VC4_HDMI_VERTB_VBP)); ++ ++ HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021); ++ HDMI_WRITE(HDMI_HORZA, ++ (vsync_pos ? VC5_HDMI_HORZA_VPOS : 0) | ++ (hsync_pos ? VC5_HDMI_HORZA_HPOS : 0) | ++ VC4_SET_FIELD(mode->hdisplay * pixel_rep, ++ VC5_HDMI_HORZA_HAP) | ++ VC4_SET_FIELD((mode->hsync_start - ++ mode->hdisplay) * pixel_rep, ++ VC5_HDMI_HORZA_HFP)); ++ ++ HDMI_WRITE(HDMI_HORZB, ++ VC4_SET_FIELD((mode->htotal - ++ mode->hsync_end) * pixel_rep, ++ VC5_HDMI_HORZB_HBP) | ++ VC4_SET_FIELD((mode->hsync_end - ++ mode->hsync_start) * pixel_rep, ++ VC5_HDMI_HORZB_HSP)); ++ ++ HDMI_WRITE(HDMI_VERTA0, verta); ++ HDMI_WRITE(HDMI_VERTA1, verta); ++ ++ HDMI_WRITE(HDMI_VERTB0, vertb_even); ++ HDMI_WRITE(HDMI_VERTB1, vertb); ++ ++ HDMI_WRITE(HDMI_VID_CTL, ++ (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) | ++ (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW)); ++ ++ HDMI_WRITE(HDMI_CLOCK_STOP, 0); ++} ++ + static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) + { + struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; +@@ -1337,6 +1461,92 @@ static int vc4_hdmi_init_resources(struc + return 0; + } + ++static int vc5_hdmi_init_resources(struct vc4_hdmi *vc4_hdmi) ++{ ++ struct platform_device *pdev = vc4_hdmi->pdev; ++ struct device *dev = &pdev->dev; ++ struct resource *res; ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi"); ++ if (!res) ++ return -ENODEV; ++ ++ vc4_hdmi->hdmicore_regs = devm_ioremap(dev, res->start, ++ resource_size(res)); ++ if (IS_ERR(vc4_hdmi->hdmicore_regs)) ++ return PTR_ERR(vc4_hdmi->hdmicore_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hd"); ++ if (!res) ++ return -ENODEV; ++ ++ vc4_hdmi->hd_regs = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(vc4_hdmi->hd_regs)) ++ return PTR_ERR(vc4_hdmi->hd_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cec"); ++ if (!res) ++ return -ENODEV; ++ ++ vc4_hdmi->cec_regs = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(vc4_hdmi->cec_regs)) ++ return PTR_ERR(vc4_hdmi->cec_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csc"); ++ if (!res) ++ return -ENODEV; ++ ++ vc4_hdmi->csc_regs = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(vc4_hdmi->csc_regs)) ++ return PTR_ERR(vc4_hdmi->csc_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dvp"); ++ if (!res) ++ return -ENODEV; ++ ++ vc4_hdmi->dvp_regs = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(vc4_hdmi->dvp_regs)) ++ return PTR_ERR(vc4_hdmi->dvp_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); ++ if (!res) ++ return -ENODEV; ++ ++ vc4_hdmi->phy_regs = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(vc4_hdmi->phy_regs)) ++ return PTR_ERR(vc4_hdmi->phy_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "packet"); ++ if (!res) ++ return -ENODEV; ++ ++ vc4_hdmi->ram_regs = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(vc4_hdmi->ram_regs)) ++ return PTR_ERR(vc4_hdmi->ram_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rm"); ++ if (!res) ++ return -ENODEV; ++ ++ vc4_hdmi->rm_regs = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(vc4_hdmi->rm_regs)) ++ return PTR_ERR(vc4_hdmi->rm_regs); ++ ++ vc4_hdmi->hsm_clock = devm_clk_get(dev, "hdmi"); ++ if (IS_ERR(vc4_hdmi->hsm_clock)) { ++ DRM_ERROR("Failed to get HDMI state machine clock\n"); ++ return PTR_ERR(vc4_hdmi->hsm_clock); ++ } ++ ++ vc4_hdmi->reset = devm_reset_control_get(dev, NULL); ++ if (IS_ERR(vc4_hdmi->reset)) { ++ DRM_ERROR("Failed to get HDMI reset line\n"); ++ return PTR_ERR(vc4_hdmi->reset); ++ } ++ ++ return 0; ++} ++ + static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) + { + struct platform_device *pdev = to_platform_device(dev); +@@ -1492,8 +1702,52 @@ static const struct vc4_hdmi_variant bcm + .phy_rng_disable = vc4_hdmi_phy_rng_disable, + }; + ++static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = { ++ .id = 0, ++ .max_pixel_clock = 297000000, ++ .registers = vc5_hdmi_hdmi0_fields, ++ .num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields), ++ .phy_lane_mapping = { ++ PHY_LANE_0, ++ PHY_LANE_1, ++ PHY_LANE_2, ++ PHY_LANE_CK, ++ }, ++ ++ .init_resources = vc5_hdmi_init_resources, ++ .csc_setup = vc5_hdmi_csc_setup, ++ .reset = vc5_hdmi_reset, ++ .set_timings = vc5_hdmi_set_timings, ++ .phy_init = vc5_hdmi_phy_init, ++ .phy_rng_enable = vc5_hdmi_phy_rng_enable, ++ .phy_rng_disable = vc5_hdmi_phy_rng_disable, ++}; ++ ++static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = { ++ .id = 1, ++ .max_pixel_clock = 297000000, ++ .registers = vc5_hdmi_hdmi1_fields, ++ .num_registers = ARRAY_SIZE(vc5_hdmi_hdmi1_fields), ++ .phy_lane_mapping = { ++ PHY_LANE_1, ++ PHY_LANE_0, ++ PHY_LANE_CK, ++ PHY_LANE_2, ++ }, ++ ++ .init_resources = vc5_hdmi_init_resources, ++ .csc_setup = vc5_hdmi_csc_setup, ++ .reset = vc5_hdmi_reset, ++ .set_timings = vc5_hdmi_set_timings, ++ .phy_init = vc5_hdmi_phy_init, ++ .phy_rng_enable = vc5_hdmi_phy_rng_enable, ++ .phy_rng_disable = vc5_hdmi_phy_rng_disable, ++}; ++ + static const struct of_device_id vc4_hdmi_dt_match[] = { + { .compatible = "brcm,bcm2835-hdmi", .data = &bcm2835_variant }, ++ { .compatible = "brcm,bcm2711-hdmi0", .data = &bcm2711_hdmi0_variant }, ++ { .compatible = "brcm,bcm2711-hdmi1", .data = &bcm2711_hdmi1_variant }, + {} + }; + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -26,6 +26,13 @@ struct drm_display_mode; + struct vc4_hdmi; + struct vc4_hdmi_register; + ++enum vc4_hdmi_phy_channel { ++ PHY_LANE_0 = 0, ++ PHY_LANE_1, ++ PHY_LANE_2, ++ PHY_LANE_CK, ++}; ++ + struct vc4_hdmi_variant { + /* On devices that have multiple, different instances (like + * the BCM2711), which instance is that variant useful for. +@@ -47,6 +54,13 @@ struct vc4_hdmi_variant { + /* Number of registers on that variant */ + unsigned int num_registers; + ++ /* BCM2711 Only. ++ * The variants don't map the lane in the same order in the ++ * PHY, so this is an array mapping the HDMI channel (index) ++ * to the PHY lane (value). ++ */ ++ enum vc4_hdmi_phy_channel phy_lane_mapping[4]; ++ + /* Callback to get the resources (memory region, interrupts, + * clocks, etc) for that variant. + */ +@@ -102,6 +116,20 @@ struct vc4_hdmi { + struct i2c_adapter *ddc; + void __iomem *hdmicore_regs; + void __iomem *hd_regs; ++ ++ /* VC5 Only */ ++ void __iomem *cec_regs; ++ /* VC5 Only */ ++ void __iomem *csc_regs; ++ /* VC5 Only */ ++ void __iomem *dvp_regs; ++ /* VC5 Only */ ++ void __iomem *phy_regs; ++ /* VC5 Only */ ++ void __iomem *ram_regs; ++ /* VC5 Only */ ++ void __iomem *rm_regs; ++ + int hpd_gpio; + bool hpd_active_low; + +@@ -113,6 +141,8 @@ struct vc4_hdmi { + struct clk *pixel_clock; + struct clk *hsm_clock; + ++ struct reset_control *reset; ++ + struct debugfs_regset32 hdmi_regset; + struct debugfs_regset32 hd_regset; + }; +@@ -137,4 +167,9 @@ void vc4_hdmi_phy_disable(struct vc4_hdm + void vc4_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi); + void vc4_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi); + ++void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, ++ struct drm_display_mode *mode); ++void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi); ++void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi); ++ + #endif /* _VC4_HDMI_H_ */ +--- a/drivers/gpu/drm/vc4/vc4_hdmi_phy.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi_phy.c +@@ -10,6 +10,123 @@ + #include "vc4_regs.h" + #include "vc4_hdmi_regs.h" + ++#define VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB BIT(5) ++#define VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB BIT(4) ++#define VC4_HDMI_TX_PHY_RESET_CTL_TX_CK_RESET BIT(3) ++#define VC4_HDMI_TX_PHY_RESET_CTL_TX_2_RESET BIT(2) ++#define VC4_HDMI_TX_PHY_RESET_CTL_TX_1_RESET BIT(1) ++#define VC4_HDMI_TX_PHY_RESET_CTL_TX_0_RESET BIT(0) ++ ++#define VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN BIT(4) ++ ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_PREEMP_SHIFT 29 ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_PREEMP_MASK VC4_MASK(31, 29) ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_MAINDRV_SHIFT 24 ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_MAINDRV_MASK VC4_MASK(28, 24) ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_PREEMP_SHIFT 21 ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_PREEMP_MASK VC4_MASK(23, 21) ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_MAINDRV_SHIFT 16 ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_MAINDRV_MASK VC4_MASK(20, 16) ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_PREEMP_SHIFT 13 ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_PREEMP_MASK VC4_MASK(15, 13) ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_MAINDRV_SHIFT 8 ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_MAINDRV_MASK VC4_MASK(12, 8) ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_PREEMP_SHIFT 5 ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_PREEMP_MASK VC4_MASK(7, 5) ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_MAINDRV_SHIFT 0 ++#define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_MAINDRV_MASK VC4_MASK(4, 0) ++ ++#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA2_SHIFT 15 ++#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA2_MASK VC4_MASK(19, 15) ++#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA1_SHIFT 10 ++#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA1_MASK VC4_MASK(14, 10) ++#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA0_SHIFT 5 ++#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA0_MASK VC4_MASK(9, 5) ++#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_CK_SHIFT 0 ++#define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_CK_MASK VC4_MASK(4, 0) ++ ++#define VC4_HDMI_TX_PHY_CTL_2_VCO_GAIN_SHIFT 16 ++#define VC4_HDMI_TX_PHY_CTL_2_VCO_GAIN_MASK VC4_MASK(19, 16) ++#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA2_SHIFT 12 ++#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA2_MASK VC4_MASK(15, 12) ++#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA1_SHIFT 8 ++#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA1_MASK VC4_MASK(11, 8) ++#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA0_SHIFT 4 ++#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA0_MASK VC4_MASK(7, 4) ++#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELCK_SHIFT 0 ++#define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELCK_MASK VC4_MASK(3, 0) ++ ++#define VC4_HDMI_TX_PHY_CTL_3_RP_SHIFT 17 ++#define VC4_HDMI_TX_PHY_CTL_3_RP_MASK VC4_MASK(19, 17) ++#define VC4_HDMI_TX_PHY_CTL_3_RZ_SHIFT 12 ++#define VC4_HDMI_TX_PHY_CTL_3_RZ_MASK VC4_MASK(16, 12) ++#define VC4_HDMI_TX_PHY_CTL_3_CP1_SHIFT 10 ++#define VC4_HDMI_TX_PHY_CTL_3_CP1_MASK VC4_MASK(11, 10) ++#define VC4_HDMI_TX_PHY_CTL_3_CP_SHIFT 8 ++#define VC4_HDMI_TX_PHY_CTL_3_CP_MASK VC4_MASK(9, 8) ++#define VC4_HDMI_TX_PHY_CTL_3_CZ_SHIFT 6 ++#define VC4_HDMI_TX_PHY_CTL_3_CZ_MASK VC4_MASK(7, 6) ++#define VC4_HDMI_TX_PHY_CTL_3_ICP_SHIFT 0 ++#define VC4_HDMI_TX_PHY_CTL_3_ICP_MASK VC4_MASK(5, 0) ++ ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_MASH11_MODE BIT(13) ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_VC_RANGE_EN BIT(12) ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_EMULATE_VC_LOW BIT(11) ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_EMULATE_VC_HIGH BIT(10) ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_SEL_SHIFT 9 ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_SEL_MASK VC4_MASK(9, 9) ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_FB_DIV2 BIT(8) ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_POST_DIV2 BIT(7) ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_CONT_EN BIT(6) ++#define VC4_HDMI_TX_PHY_PLL_CTL_0_ENA_VCO_CLK BIT(5) ++ ++#define VC4_HDMI_TX_PHY_PLL_CTL_1_CPP_SHIFT 16 ++#define VC4_HDMI_TX_PHY_PLL_CTL_1_CPP_MASK VC4_MASK(27, 16) ++#define VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_DELAY_SHIFT 14 ++#define VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_DELAY_MASK VC4_MASK(15, 14) ++#define VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_ENABLE BIT(13) ++#define VC4_HDMI_TX_PHY_PLL_CTL_1_POST_RST_SEL_SHIFT 11 ++#define VC4_HDMI_TX_PHY_PLL_CTL_1_POST_RST_SEL_MASK VC4_MASK(12, 11) ++ ++#define VC4_HDMI_TX_PHY_CLK_DIV_VCO_SHIFT 8 ++#define VC4_HDMI_TX_PHY_CLK_DIV_VCO_MASK VC4_MASK(15, 8) ++ ++#define VC4_HDMI_TX_PHY_PLL_CFG_PDIV_SHIFT 0 ++#define VC4_HDMI_TX_PHY_PLL_CFG_PDIV_MASK VC4_MASK(3, 0) ++ ++#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TXCK_OUT_SEL_MASK VC4_MASK(13, 12) ++#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TXCK_OUT_SEL_SHIFT 12 ++#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX2_OUT_SEL_MASK VC4_MASK(9, 8) ++#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX2_OUT_SEL_SHIFT 8 ++#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX1_OUT_SEL_MASK VC4_MASK(5, 4) ++#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX1_OUT_SEL_SHIFT 4 ++#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX0_OUT_SEL_MASK VC4_MASK(1, 0) ++#define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX0_OUT_SEL_SHIFT 0 ++ ++#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT_MASK VC4_MASK(27, 0) ++#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT_SHIFT 0 ++ ++#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT_MASK VC4_MASK(27, 0) ++#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT_SHIFT 0 ++ ++#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_STABLE_THRESHOLD_MASK VC4_MASK(31, 16) ++#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_STABLE_THRESHOLD_SHIFT 16 ++#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_HOLD_THRESHOLD_MASK VC4_MASK(15, 0) ++#define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_HOLD_THRESHOLD_SHIFT 0 ++ ++#define VC4_HDMI_RM_CONTROL_EN_FREEZE_COUNTERS BIT(19) ++#define VC4_HDMI_RM_CONTROL_EN_LOAD_INTEGRATOR BIT(17) ++#define VC4_HDMI_RM_CONTROL_FREE_RUN BIT(4) ++ ++#define VC4_HDMI_RM_OFFSET_ONLY BIT(31) ++#define VC4_HDMI_RM_OFFSET_OFFSET_SHIFT 0 ++#define VC4_HDMI_RM_OFFSET_OFFSET_MASK VC4_MASK(30, 0) ++ ++#define VC4_HDMI_RM_FORMAT_SHIFT_SHIFT 24 ++#define VC4_HDMI_RM_FORMAT_SHIFT_MASK VC4_MASK(25, 24) ++ ++#define OSCILLATOR_FREQUENCY 54000000 ++ + void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct drm_display_mode *mode) + { + /* PHY should be in reset, like +@@ -38,3 +155,355 @@ void vc4_hdmi_phy_rng_disable(struct vc4 + HDMI_READ(HDMI_TX_PHY_CTL_0) | + VC4_HDMI_TX_PHY_RNG_PWRDN); + } ++ ++static unsigned long long ++phy_get_vco_freq(unsigned long long clock, u8 *vco_sel, u8 *vco_div) ++{ ++ unsigned long long vco_freq = clock; ++ unsigned int _vco_div = 0; ++ unsigned int _vco_sel = 0; ++ ++ while (vco_freq < 3000000000ULL) { ++ _vco_div++; ++ vco_freq = clock * _vco_div * 10; ++ } ++ ++ if (vco_freq > 4500000000ULL) ++ _vco_sel = 1; ++ ++ *vco_sel = _vco_sel; ++ *vco_div = _vco_div; ++ ++ return vco_freq; ++} ++ ++static u8 phy_get_cp_current(unsigned long vco_freq) ++{ ++ if (vco_freq < 3700000000ULL) ++ return 0x1c; ++ ++ return 0xc8; ++} ++ ++static u32 phy_get_rm_offset(unsigned long long vco_freq) ++{ ++ unsigned long long fref = OSCILLATOR_FREQUENCY; ++ uint64_t offset = 0; ++ ++ /* RM offset is stored as 9.22 format */ ++ offset = vco_freq * 2; ++ do_div(offset, fref); ++ offset = offset << 22; ++ offset >>= 2; ++ ++ return offset; ++} ++ ++static u8 phy_get_vco_gain(unsigned long long vco_freq) ++{ ++ if (vco_freq < 3350000000ULL) ++ return 0xf; ++ ++ if (vco_freq < 3700000000ULL) ++ return 0xc; ++ ++ if (vco_freq < 4050000000ULL) ++ return 0x6; ++ ++ if (vco_freq < 4800000000ULL) ++ return 0x5; ++ ++ if (vco_freq < 5200000000ULL) ++ return 0x7; ++ ++ return 0x2; ++} ++ ++struct phy_lane_settings { ++ struct { ++ u8 preemphasis; ++ u8 main_driver; ++ } amplitude; ++ ++ u8 res_sel_data; ++ u8 term_res_sel_data; ++}; ++ ++struct phy_settings { ++ unsigned long long min_rate; ++ unsigned long long max_rate; ++ struct phy_lane_settings channel[3]; ++ struct phy_lane_settings clock; ++}; ++ ++static const struct phy_settings vc5_hdmi_phy_settings[] = ++{ ++ { ++ 0, 50000000, ++ { ++ {{0x0, 0x0A}, 0x12, 0x0}, ++ {{0x0, 0x0A}, 0x12, 0x0}, ++ {{0x0, 0x0A}, 0x12, 0x0} ++ }, ++ {{0x0, 0x0A}, 0x18, 0x0}, ++ }, ++ { ++ 50000001, 75000000, ++ { ++ {{0x0, 0x09}, 0x12, 0x0}, ++ {{0x0, 0x09}, 0x12, 0x0}, ++ {{0x0, 0x09}, 0x12, 0x0} ++ }, ++ {{0x0, 0x0C}, 0x18, 0x3}, ++ }, ++ { ++ 75000001, 165000000, ++ { ++ {{0x0, 0x09}, 0x12, 0x0}, ++ {{0x0, 0x09}, 0x12, 0x0}, ++ {{0x0, 0x09}, 0x12, 0x0} ++ }, ++ {{0x0, 0x0C}, 0x18, 0x3}, ++ }, ++ { ++ 165000001, 250000000, ++ { ++ {{0x0, 0x0F}, 0x12, 0x1}, ++ {{0x0, 0x0F}, 0x12, 0x1}, ++ {{0x0, 0x0F}, 0x12, 0x1} ++ }, ++ {{0x0, 0x0C}, 0x18, 0x3}, ++ }, ++ { ++ 250000001, 340000000, ++ { ++ {{0x2, 0x0D}, 0x12, 0x1}, ++ {{0x2, 0x0D}, 0x12, 0x1}, ++ {{0x2, 0x0D}, 0x12, 0x1} ++ }, ++ {{0x0, 0x0C}, 0x18, 0xF}, ++ }, ++ { ++ 340000001, 450000000, ++ { ++ {{0x0, 0x1B}, 0x12, 0xF}, ++ {{0x0, 0x1B}, 0x12, 0xF}, ++ {{0x0, 0x1B}, 0x12, 0xF} ++ }, ++ {{0x0, 0x0A}, 0x12, 0xF}, ++ }, ++ { ++ 450000001, 600000000, ++ { ++ {{0x0, 0x1C}, 0x12, 0xF}, ++ {{0x0, 0x1C}, 0x12, 0xF}, ++ {{0x0, 0x1C}, 0x12, 0xF} ++ }, ++ {{0x0, 0x0B}, 0x13, 0xF}, ++ }, ++}; ++ ++static const struct phy_settings *phy_get_settings(unsigned long long tmds_rate) ++{ ++ unsigned int count = ARRAY_SIZE(vc5_hdmi_phy_settings); ++ unsigned int i; ++ ++ for (i = 0; i < count; i++) { ++ const struct phy_settings *s = &vc5_hdmi_phy_settings[i]; ++ ++ if (tmds_rate >= s->min_rate && tmds_rate <= s->max_rate) ++ return s; ++ } ++ ++ /* ++ * If the pixel clock exceeds our max setting, try the max ++ * setting anyway. ++ */ ++ return &vc5_hdmi_phy_settings[count - 1]; ++} ++ ++static const struct phy_lane_settings * ++phy_get_channel_settings(enum vc4_hdmi_phy_channel chan, ++ unsigned long long tmds_rate) ++{ ++ const struct phy_settings *settings = phy_get_settings(tmds_rate); ++ ++ if (chan == PHY_LANE_CK) ++ return &settings->clock; ++ ++ return &settings->channel[chan]; ++} ++ ++void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct drm_display_mode *mode) ++{ ++ const struct phy_lane_settings *chan0_settings, *chan1_settings, *chan2_settings, *clock_settings; ++ const struct vc4_hdmi_variant *variant = vc4_hdmi->variant; ++ unsigned long long pixel_freq = mode->clock * 1000; ++ unsigned long long vco_freq; ++ unsigned char word_sel; ++ u8 vco_sel, vco_div; ++ ++ vco_freq = phy_get_vco_freq(pixel_freq, &vco_sel, &vco_div); ++ ++ HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, ++ VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN); ++ ++ HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, ++ HDMI_READ(HDMI_TX_PHY_RESET_CTL) & ++ ~VC4_HDMI_TX_PHY_RESET_CTL_TX_0_RESET & ++ ~VC4_HDMI_TX_PHY_RESET_CTL_TX_1_RESET & ++ ~VC4_HDMI_TX_PHY_RESET_CTL_TX_2_RESET & ++ ~VC4_HDMI_TX_PHY_RESET_CTL_TX_CK_RESET); ++ ++ HDMI_WRITE(HDMI_RM_CONTROL, ++ HDMI_READ(HDMI_RM_CONTROL) | ++ VC4_HDMI_RM_CONTROL_EN_FREEZE_COUNTERS | ++ VC4_HDMI_RM_CONTROL_EN_LOAD_INTEGRATOR | ++ VC4_HDMI_RM_CONTROL_FREE_RUN); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1, ++ (HDMI_READ(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1) & ++ ~VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT_MASK) | ++ VC4_SET_FIELD(0, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2, ++ (HDMI_READ(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2) & ++ ~VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT_MASK) | ++ VC4_SET_FIELD(0, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT)); ++ ++ HDMI_WRITE(HDMI_RM_OFFSET, ++ VC4_SET_FIELD(phy_get_rm_offset(vco_freq), ++ VC4_HDMI_RM_OFFSET_OFFSET) | ++ VC4_HDMI_RM_OFFSET_ONLY); ++ ++ HDMI_WRITE(HDMI_TX_PHY_CLK_DIV, ++ VC4_SET_FIELD(vco_div, VC4_HDMI_TX_PHY_CLK_DIV_VCO)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4, ++ VC4_SET_FIELD(0xe147, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_HOLD_THRESHOLD) | ++ VC4_SET_FIELD(0xe14, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_STABLE_THRESHOLD)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_CTL_0, ++ VC4_HDMI_TX_PHY_PLL_CTL_0_ENA_VCO_CLK | ++ VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_CONT_EN | ++ VC4_HDMI_TX_PHY_PLL_CTL_0_MASH11_MODE | ++ VC4_SET_FIELD(vco_sel, VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_SEL)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_CTL_1, ++ HDMI_READ(HDMI_TX_PHY_PLL_CTL_1) | ++ VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_ENABLE | ++ VC4_SET_FIELD(3, VC4_HDMI_TX_PHY_PLL_CTL_1_POST_RST_SEL) | ++ VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_DELAY) | ++ VC4_SET_FIELD(0x8a, VC4_HDMI_TX_PHY_PLL_CTL_1_CPP)); ++ ++ HDMI_WRITE(HDMI_RM_FORMAT, ++ HDMI_READ(HDMI_RM_FORMAT) | ++ VC4_SET_FIELD(2, VC4_HDMI_RM_FORMAT_SHIFT)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_PLL_CFG, ++ HDMI_READ(HDMI_TX_PHY_PLL_CFG) | ++ VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_PLL_CFG_PDIV)); ++ ++ if (pixel_freq >= 340000000) ++ word_sel = 3; ++ else ++ word_sel = 0; ++ HDMI_WRITE(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, word_sel); ++ ++ HDMI_WRITE(HDMI_TX_PHY_CTL_3, ++ VC4_SET_FIELD(phy_get_cp_current(vco_freq), ++ VC4_HDMI_TX_PHY_CTL_3_ICP) | ++ VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_CTL_3_CP) | ++ VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_CTL_3_CP1) | ++ VC4_SET_FIELD(3, VC4_HDMI_TX_PHY_CTL_3_CZ) | ++ VC4_SET_FIELD(4, VC4_HDMI_TX_PHY_CTL_3_RP) | ++ VC4_SET_FIELD(6, VC4_HDMI_TX_PHY_CTL_3_RZ)); ++ ++ chan0_settings = ++ phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_0], ++ pixel_freq); ++ chan1_settings = ++ phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_1], ++ pixel_freq); ++ chan2_settings = ++ phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_2], ++ pixel_freq); ++ clock_settings = ++ phy_get_channel_settings(variant->phy_lane_mapping[PHY_LANE_CK], ++ pixel_freq); ++ ++ HDMI_WRITE(HDMI_TX_PHY_CTL_0, ++ VC4_SET_FIELD(chan0_settings->amplitude.preemphasis, ++ VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_PREEMP) | ++ VC4_SET_FIELD(chan0_settings->amplitude.main_driver, ++ VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_MAINDRV) | ++ VC4_SET_FIELD(chan1_settings->amplitude.preemphasis, ++ VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_PREEMP) | ++ VC4_SET_FIELD(chan1_settings->amplitude.main_driver, ++ VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_MAINDRV) | ++ VC4_SET_FIELD(chan2_settings->amplitude.preemphasis, ++ VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_PREEMP) | ++ VC4_SET_FIELD(chan2_settings->amplitude.main_driver, ++ VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_MAINDRV) | ++ VC4_SET_FIELD(clock_settings->amplitude.preemphasis, ++ VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_PREEMP) | ++ VC4_SET_FIELD(clock_settings->amplitude.main_driver, ++ VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_MAINDRV)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_CTL_1, ++ HDMI_READ(HDMI_TX_PHY_CTL_1) | ++ VC4_SET_FIELD(chan0_settings->res_sel_data, ++ VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA0) | ++ VC4_SET_FIELD(chan1_settings->res_sel_data, ++ VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA1) | ++ VC4_SET_FIELD(chan2_settings->res_sel_data, ++ VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA2) | ++ VC4_SET_FIELD(clock_settings->res_sel_data, ++ VC4_HDMI_TX_PHY_CTL_1_RES_SEL_CK)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_CTL_2, ++ VC4_SET_FIELD(chan0_settings->term_res_sel_data, ++ VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA0) | ++ VC4_SET_FIELD(chan1_settings->term_res_sel_data, ++ VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA1) | ++ VC4_SET_FIELD(chan2_settings->term_res_sel_data, ++ VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA2) | ++ VC4_SET_FIELD(clock_settings->term_res_sel_data, ++ VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELCK) | ++ VC4_SET_FIELD(phy_get_vco_gain(vco_freq), ++ VC4_HDMI_TX_PHY_CTL_2_VCO_GAIN)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_CHANNEL_SWAP, ++ VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_0], ++ VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX0_OUT_SEL) | ++ VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_1], ++ VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX1_OUT_SEL) | ++ VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_2], ++ VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX2_OUT_SEL) | ++ VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_CK], ++ VC4_HDMI_TX_PHY_CHANNEL_SWAP_TXCK_OUT_SEL)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, ++ HDMI_READ(HDMI_TX_PHY_RESET_CTL) & ++ ~(VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB | ++ VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB)); ++ ++ HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, ++ HDMI_READ(HDMI_TX_PHY_RESET_CTL) | ++ VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB | ++ VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB); ++} ++ ++void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi) ++{ ++ HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, ++ HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) & ++ ~VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN); ++} ++ ++void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi) ++{ ++ HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, ++ HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) | ++ VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN); ++} +--- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h +@@ -18,6 +18,12 @@ enum vc4_hdmi_regs { + VC4_INVALID = 0, + VC4_HDMI, + VC4_HD, ++ VC5_CEC, ++ VC5_CSC, ++ VC5_DVP, ++ VC5_PHY, ++ VC5_RAM, ++ VC5_RM, + }; + + enum vc4_hdmi_field { +@@ -45,6 +51,7 @@ enum vc4_hdmi_field { + HDMI_CEC_TX_DATA_2, + HDMI_CEC_TX_DATA_3, + HDMI_CEC_TX_DATA_4, ++ HDMI_CLOCK_STOP, + HDMI_CORE_REV, + HDMI_CRP_CFG, + HDMI_CSC_12_11, +@@ -61,6 +68,7 @@ enum vc4_hdmi_field { + */ + HDMI_CTS_0, + HDMI_CTS_1, ++ HDMI_DVP_CTL, + HDMI_FIFO_CTL, + HDMI_FRAME_COUNT, + HDMI_HORZA, +@@ -93,10 +101,27 @@ enum vc4_hdmi_field { + HDMI_RAM_PACKET_CONFIG, + HDMI_RAM_PACKET_START, + HDMI_RAM_PACKET_STATUS, ++ HDMI_RM_CONTROL, ++ HDMI_RM_FORMAT, ++ HDMI_RM_OFFSET, + HDMI_SCHEDULER_CONTROL, + HDMI_SW_RESET_CONTROL, ++ HDMI_TX_PHY_CHANNEL_SWAP, ++ HDMI_TX_PHY_CLK_DIV, + HDMI_TX_PHY_CTL_0, ++ HDMI_TX_PHY_CTL_1, ++ HDMI_TX_PHY_CTL_2, ++ HDMI_TX_PHY_CTL_3, ++ HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1, ++ HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2, ++ HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4, ++ HDMI_TX_PHY_PLL_CFG, ++ HDMI_TX_PHY_PLL_CTL_0, ++ HDMI_TX_PHY_PLL_CTL_1, ++ HDMI_TX_PHY_POWERDOWN_CTL, + HDMI_TX_PHY_RESET_CTL, ++ HDMI_TX_PHY_TMDS_CLK_WORD_SEL, ++ HDMI_VEC_INTERFACE_XBAR, + HDMI_VERTA0, + HDMI_VERTA1, + HDMI_VERTB0, +@@ -119,6 +144,12 @@ struct vc4_hdmi_register { + + #define VC4_HD_REG(reg, offset) _VC4_REG(VC4_HD, reg, offset) + #define VC4_HDMI_REG(reg, offset) _VC4_REG(VC4_HDMI, reg, offset) ++#define VC5_CEC_REG(reg, offset) _VC4_REG(VC5_CEC, reg, offset) ++#define VC5_CSC_REG(reg, offset) _VC4_REG(VC5_CSC, reg, offset) ++#define VC5_DVP_REG(reg, offset) _VC4_REG(VC5_DVP, reg, offset) ++#define VC5_PHY_REG(reg, offset) _VC4_REG(VC5_PHY, reg, offset) ++#define VC5_RAM_REG(reg, offset) _VC4_REG(VC5_RAM, reg, offset) ++#define VC5_RM_REG(reg, offset) _VC4_REG(VC5_RM, reg, offset) + + static const struct vc4_hdmi_register vc4_hdmi_fields[] = { + VC4_HD_REG(HDMI_M_CTL, 0x000c), +@@ -181,6 +212,158 @@ static const struct vc4_hdmi_register vc + VC4_HDMI_REG(HDMI_RAM_PACKET_START, 0x0400), + }; + ++static const struct vc4_hdmi_register vc5_hdmi_hdmi0_fields[] = { ++ VC4_HD_REG(HDMI_DVP_CTL, 0x0000), ++ VC4_HD_REG(HDMI_MAI_CTL, 0x0010), ++ VC4_HD_REG(HDMI_MAI_THR, 0x0014), ++ VC4_HD_REG(HDMI_MAI_FMT, 0x0018), ++ VC4_HD_REG(HDMI_MAI_DATA, 0x001c), ++ VC4_HD_REG(HDMI_MAI_SMP, 0x0020), ++ VC4_HD_REG(HDMI_VID_CTL, 0x0044), ++ VC4_HD_REG(HDMI_FRAME_COUNT, 0x0060), ++ ++ VC4_HDMI_REG(HDMI_FIFO_CTL, 0x074), ++ VC4_HDMI_REG(HDMI_AUDIO_PACKET_CONFIG, 0x0b8), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_CONFIG, 0x0bc), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_STATUS, 0x0c4), ++ VC4_HDMI_REG(HDMI_CRP_CFG, 0x0c8), ++ VC4_HDMI_REG(HDMI_CTS_0, 0x0cc), ++ VC4_HDMI_REG(HDMI_CTS_1, 0x0d0), ++ VC4_HDMI_REG(HDMI_SCHEDULER_CONTROL, 0x0e0), ++ VC4_HDMI_REG(HDMI_HORZA, 0x0e4), ++ VC4_HDMI_REG(HDMI_HORZB, 0x0e8), ++ VC4_HDMI_REG(HDMI_VERTA0, 0x0ec), ++ VC4_HDMI_REG(HDMI_VERTB0, 0x0f0), ++ VC4_HDMI_REG(HDMI_VERTA1, 0x0f4), ++ VC4_HDMI_REG(HDMI_VERTB1, 0x0f8), ++ VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c), ++ VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0), ++ VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8), ++ ++ VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc), ++ VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0), ++ ++ VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000), ++ VC5_PHY_REG(HDMI_TX_PHY_POWERDOWN_CTL, 0x004), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_0, 0x008), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_1, 0x00c), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_2, 0x010), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_3, 0x014), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CTL_0, 0x01c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CTL_1, 0x020), ++ VC5_PHY_REG(HDMI_TX_PHY_CLK_DIV, 0x028), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CFG, 0x034), ++ VC5_PHY_REG(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, 0x044), ++ VC5_PHY_REG(HDMI_TX_PHY_CHANNEL_SWAP, 0x04c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1, 0x050), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2, 0x054), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4, 0x05c), ++ ++ VC5_RM_REG(HDMI_RM_CONTROL, 0x000), ++ VC5_RM_REG(HDMI_RM_OFFSET, 0x018), ++ VC5_RM_REG(HDMI_RM_FORMAT, 0x01c), ++ ++ VC5_RAM_REG(HDMI_RAM_PACKET_START, 0x000), ++ ++ VC5_CEC_REG(HDMI_CEC_CNTRL_1, 0x010), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_2, 0x014), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_3, 0x018), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_4, 0x01c), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_5, 0x020), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_1, 0x028), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_2, 0x02c), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_3, 0x030), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_4, 0x034), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_1, 0x038), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_2, 0x03c), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_3, 0x040), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_4, 0x044), ++ ++ VC5_CSC_REG(HDMI_CSC_CTL, 0x000), ++ VC5_CSC_REG(HDMI_CSC_12_11, 0x004), ++ VC5_CSC_REG(HDMI_CSC_14_13, 0x008), ++ VC5_CSC_REG(HDMI_CSC_22_21, 0x00c), ++ VC5_CSC_REG(HDMI_CSC_24_23, 0x010), ++ VC5_CSC_REG(HDMI_CSC_32_31, 0x014), ++ VC5_CSC_REG(HDMI_CSC_34_33, 0x018), ++}; ++ ++static const struct vc4_hdmi_register vc5_hdmi_hdmi1_fields[] = { ++ VC4_HD_REG(HDMI_DVP_CTL, 0x0000), ++ VC4_HD_REG(HDMI_MAI_CTL, 0x0030), ++ VC4_HD_REG(HDMI_MAI_THR, 0x0034), ++ VC4_HD_REG(HDMI_MAI_FMT, 0x0038), ++ VC4_HD_REG(HDMI_MAI_DATA, 0x003c), ++ VC4_HD_REG(HDMI_MAI_SMP, 0x0040), ++ VC4_HD_REG(HDMI_VID_CTL, 0x0048), ++ VC4_HD_REG(HDMI_FRAME_COUNT, 0x0064), ++ ++ VC4_HDMI_REG(HDMI_FIFO_CTL, 0x074), ++ VC4_HDMI_REG(HDMI_AUDIO_PACKET_CONFIG, 0x0b8), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_CONFIG, 0x0bc), ++ VC4_HDMI_REG(HDMI_RAM_PACKET_STATUS, 0x0c4), ++ VC4_HDMI_REG(HDMI_CRP_CFG, 0x0c8), ++ VC4_HDMI_REG(HDMI_CTS_0, 0x0cc), ++ VC4_HDMI_REG(HDMI_CTS_1, 0x0d0), ++ VC4_HDMI_REG(HDMI_SCHEDULER_CONTROL, 0x0e0), ++ VC4_HDMI_REG(HDMI_HORZA, 0x0e4), ++ VC4_HDMI_REG(HDMI_HORZB, 0x0e8), ++ VC4_HDMI_REG(HDMI_VERTA0, 0x0ec), ++ VC4_HDMI_REG(HDMI_VERTB0, 0x0f0), ++ VC4_HDMI_REG(HDMI_VERTA1, 0x0f4), ++ VC4_HDMI_REG(HDMI_VERTB1, 0x0f8), ++ VC4_HDMI_REG(HDMI_MAI_CHANNEL_MAP, 0x09c), ++ VC4_HDMI_REG(HDMI_MAI_CONFIG, 0x0a0), ++ VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8), ++ ++ VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc), ++ VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0), ++ ++ VC5_PHY_REG(HDMI_TX_PHY_RESET_CTL, 0x000), ++ VC5_PHY_REG(HDMI_TX_PHY_POWERDOWN_CTL, 0x004), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_0, 0x008), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_1, 0x00c), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_2, 0x010), ++ VC5_PHY_REG(HDMI_TX_PHY_CTL_3, 0x014), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CTL_0, 0x01c), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CTL_1, 0x020), ++ VC5_PHY_REG(HDMI_TX_PHY_CLK_DIV, 0x028), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CFG, 0x034), ++ VC5_PHY_REG(HDMI_TX_PHY_CHANNEL_SWAP, 0x04c), ++ VC5_PHY_REG(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, 0x044), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1, 0x050), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2, 0x054), ++ VC5_PHY_REG(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4, 0x05c), ++ ++ VC5_RM_REG(HDMI_RM_CONTROL, 0x000), ++ VC5_RM_REG(HDMI_RM_OFFSET, 0x018), ++ VC5_RM_REG(HDMI_RM_FORMAT, 0x01c), ++ ++ VC5_RAM_REG(HDMI_RAM_PACKET_START, 0x000), ++ ++ VC5_CEC_REG(HDMI_CEC_CNTRL_1, 0x010), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_2, 0x014), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_3, 0x018), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_4, 0x01c), ++ VC5_CEC_REG(HDMI_CEC_CNTRL_5, 0x020), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_1, 0x028), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_2, 0x02c), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_3, 0x030), ++ VC5_CEC_REG(HDMI_CEC_TX_DATA_4, 0x034), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_1, 0x038), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_2, 0x03c), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_3, 0x040), ++ VC5_CEC_REG(HDMI_CEC_RX_DATA_4, 0x044), ++ ++ VC5_CSC_REG(HDMI_CSC_CTL, 0x000), ++ VC5_CSC_REG(HDMI_CSC_12_11, 0x004), ++ VC5_CSC_REG(HDMI_CSC_14_13, 0x008), ++ VC5_CSC_REG(HDMI_CSC_22_21, 0x00c), ++ VC5_CSC_REG(HDMI_CSC_24_23, 0x010), ++ VC5_CSC_REG(HDMI_CSC_32_31, 0x014), ++ VC5_CSC_REG(HDMI_CSC_34_33, 0x018), ++}; ++ + static inline + void __iomem *__vc4_hdmi_get_field_base(struct vc4_hdmi *hdmi, + enum vc4_hdmi_regs reg) +@@ -192,6 +375,24 @@ void __iomem *__vc4_hdmi_get_field_base( + case VC4_HDMI: + return hdmi->hdmicore_regs; + ++ case VC5_CSC: ++ return hdmi->csc_regs; ++ ++ case VC5_CEC: ++ return hdmi->cec_regs; ++ ++ case VC5_DVP: ++ return hdmi->dvp_regs; ++ ++ case VC5_PHY: ++ return hdmi->phy_regs; ++ ++ case VC5_RAM: ++ return hdmi->ram_regs; ++ ++ case VC5_RM: ++ return hdmi->rm_regs; ++ + default: + return NULL; + } |