drm/amd/display: get refclk from MICROSECOND_TIME_BASE_DIV HW register
authorCharlene Liu <Charlene.Liu@amd.com>
Tue, 25 May 2021 18:06:37 +0000 (14:06 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 21 Jun 2021 21:45:14 +0000 (17:45 -0400)
[why]
recent VBIOS dce_infotable reference clock change caused a I2c regression.
instead of relying on vbios, let's get it from HW directly.

Signed-off-by: Charlene Liu <Charlene.Liu@amd.com>
Reviewed-by: Chris Park <Chris.Park@amd.com>
Reviewed-by: Nicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Acked-by: Bindu Ramamurthy <bindu.r@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c
drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h

index a524f471e0d75c70bcf7222f59d7927ba8185d6b..6d1b01c267b751c14a03b39289f0206f051a93ad 100644 (file)
@@ -264,18 +264,25 @@ static void set_speed(
        struct dce_i2c_hw *dce_i2c_hw,
        uint32_t speed)
 {
-       uint32_t xtal_ref_div = 0;
+       uint32_t xtal_ref_div = 0, ref_base_div = 0;
        uint32_t prescale = 0;
+       uint32_t i2c_ref_clock = 0;
 
        if (speed == 0)
                return;
 
-       REG_GET(MICROSECOND_TIME_BASE_DIV, XTAL_REF_DIV, &xtal_ref_div);
+       REG_GET_2(MICROSECOND_TIME_BASE_DIV, MICROSECOND_TIME_BASE_DIV, &ref_base_div,
+               XTAL_REF_DIV, &xtal_ref_div);
 
        if (xtal_ref_div == 0)
                xtal_ref_div = 2;
 
-       prescale = ((dce_i2c_hw->reference_frequency * 2) / xtal_ref_div) / speed;
+       if (ref_base_div == 0)
+               i2c_ref_clock = (dce_i2c_hw->reference_frequency * 2);
+       else
+               i2c_ref_clock = ref_base_div * 1000;
+
+       prescale = (i2c_ref_clock / xtal_ref_div) / speed;
 
        if (dce_i2c_hw->masks->DC_I2C_DDC1_START_STOP_TIMING_CNTL)
                REG_UPDATE_N(SPEED, 3,
index 2309f2bb162c055d24658ed773999b349af92746..3f45ecd189a26c79d4cf056278a981f4ed6acb8d 100644 (file)
@@ -139,6 +139,7 @@ enum {
        I2C_SF(DC_I2C_DATA, DC_I2C_INDEX, mask_sh),\
        I2C_SF(DC_I2C_DATA, DC_I2C_INDEX_WRITE, mask_sh),\
        I2C_SF(MICROSECOND_TIME_BASE_DIV, XTAL_REF_DIV, mask_sh),\
+       I2C_SF(MICROSECOND_TIME_BASE_DIV, MICROSECOND_TIME_BASE_DIV, mask_sh),\
        I2C_SF(DC_I2C_ARBITRATION, DC_I2C_REG_RW_CNTL_STATUS, mask_sh)
 
 #define I2C_COMMON_MASK_SH_LIST_DCE110(mask_sh)\
@@ -182,6 +183,7 @@ struct dce_i2c_shift {
        uint8_t DC_I2C_INDEX;
        uint8_t DC_I2C_INDEX_WRITE;
        uint8_t XTAL_REF_DIV;
+       uint8_t MICROSECOND_TIME_BASE_DIV;
        uint8_t DC_I2C_DDC1_SEND_RESET_LENGTH;
        uint8_t DC_I2C_REG_RW_CNTL_STATUS;
        uint8_t I2C_LIGHT_SLEEP_FORCE;
@@ -225,6 +227,7 @@ struct dce_i2c_mask {
        uint32_t DC_I2C_INDEX;
        uint32_t DC_I2C_INDEX_WRITE;
        uint32_t XTAL_REF_DIV;
+       uint32_t MICROSECOND_TIME_BASE_DIV;
        uint32_t DC_I2C_DDC1_SEND_RESET_LENGTH;
        uint32_t DC_I2C_REG_RW_CNTL_STATUS;
        uint32_t I2C_LIGHT_SLEEP_FORCE;