diff options
Diffstat (limited to 'drivers/gpu/drm/bridge')
-rw-r--r-- | drivers/gpu/drm/bridge/Kconfig | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/adv7511/adv7533.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/analogix-anx78xx.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 436 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 48 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 522 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 34 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/dumb-vga-dac.c | 223 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/dw-hdmi-ahb-audio.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/dw-hdmi.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/nxp-ptn3460.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/parade-ps8622.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/tc358767.c | 8 |
15 files changed, 719 insertions, 618 deletions
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index b590e678052d..10e12e74fc9f 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -17,6 +17,13 @@ config DRM_ANALOGIX_ANX78XX the HDMI output of an application processor to MyDP or DisplayPort. +config DRM_DUMB_VGA_DAC + tristate "Dumb VGA DAC Bridge support" + depends on OF + select DRM_KMS_HELPER + help + Support for RGB to VGA DAC based bridges + config DRM_DW_HDMI tristate select DRM_KMS_HELPER diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index efdb07e878f5..cdf3a3cf765d 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -1,6 +1,7 @@ ccflags-y := -Iinclude/drm obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o +obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index ec8fb2ed3275..8ed3906dd411 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -922,15 +922,13 @@ static int adv7511_parse_dt(struct device_node *np, return 0; } -static const int edid_i2c_addr = 0x7e; -static const int packet_i2c_addr = 0x70; -static const int cec_i2c_addr = 0x78; - static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct adv7511_link_config link_config; struct adv7511 *adv7511; struct device *dev = &i2c->dev; + unsigned int main_i2c_addr = i2c->addr << 1; + unsigned int edid_i2c_addr = main_i2c_addr + 4; unsigned int val; int ret; @@ -991,8 +989,10 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr); regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR, - packet_i2c_addr); - regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR, cec_i2c_addr); + main_i2c_addr - 0xa); + regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR, + main_i2c_addr - 2); + adv7511_packet_disable(adv7511, 0xffff); adv7511->i2c_main = i2c; diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c index 5eebd15899b1..d7f7b7ce8ebe 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7533.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c @@ -149,13 +149,12 @@ void adv7533_uninit_cec(struct adv7511 *adv) i2c_unregister_device(adv->i2c_cec); } -static const int cec_i2c_addr = 0x78; - int adv7533_init_cec(struct adv7511 *adv) { int ret; - adv->i2c_cec = i2c_new_dummy(adv->i2c_main->adapter, cec_i2c_addr >> 1); + adv->i2c_cec = i2c_new_dummy(adv->i2c_main->adapter, + adv->i2c_main->addr - 1); if (!adv->i2c_cec) return -ENOMEM; diff --git a/drivers/gpu/drm/bridge/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix-anx78xx.c index f9f03bcba0af..a2a82366a771 100644 --- a/drivers/gpu/drm/bridge/analogix-anx78xx.c +++ b/drivers/gpu/drm/bridge/analogix-anx78xx.c @@ -1001,16 +1001,11 @@ static enum drm_connector_status anx78xx_detect(struct drm_connector *connector, return connector_status_connected; } -static void anx78xx_connector_destroy(struct drm_connector *connector) -{ - drm_connector_cleanup(connector); -} - static const struct drm_connector_funcs anx78xx_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = anx78xx_detect, - .destroy = anx78xx_connector_destroy, + .destroy = drm_connector_cleanup, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715daf73cb..6e0447f329a2 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -31,6 +31,7 @@ #include <drm/bridge/analogix_dp.h> #include "analogix_dp_core.h" +#include "analogix_dp_reg.h" #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) @@ -97,133 +98,89 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) return 0; } -static unsigned char analogix_dp_calc_edid_check_sum(unsigned char *edid_data) +int analogix_dp_psr_supported(struct device *dev) { - int i; - unsigned char sum = 0; - - for (i = 0; i < EDID_BLOCK_LENGTH; i++) - sum = sum + edid_data[i]; + struct analogix_dp_device *dp = dev_get_drvdata(dev); - return sum; + return dp->psr_support; } +EXPORT_SYMBOL_GPL(analogix_dp_psr_supported); -static int analogix_dp_read_edid(struct analogix_dp_device *dp) +int analogix_dp_enable_psr(struct device *dev) { - unsigned char *edid = dp->edid; - unsigned int extend_block = 0; - unsigned char sum; - unsigned char test_vector; - int retval; + struct analogix_dp_device *dp = dev_get_drvdata(dev); + struct edp_vsc_psr psr_vsc; - /* - * EDID device address is 0x50. - * However, if necessary, you must have set upper address - * into E-EDID in I2C device, 0x30. - */ + if (!dp->psr_support) + return -EINVAL; - /* Read Extension Flag, Number of 128-byte EDID extension blocks */ - retval = analogix_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, - EDID_EXTENSION_FLAG, - &extend_block); - if (retval) - return retval; + /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ + memset(&psr_vsc, 0, sizeof(psr_vsc)); + psr_vsc.sdp_header.HB0 = 0; + psr_vsc.sdp_header.HB1 = 0x7; + psr_vsc.sdp_header.HB2 = 0x2; + psr_vsc.sdp_header.HB3 = 0x8; - if (extend_block > 0) { - dev_dbg(dp->dev, "EDID data includes a single extension!\n"); - - /* Read EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, - &edid[EDID_HEADER_PATTERN]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum(edid); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } + psr_vsc.DB0 = 0; + psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; - /* Read additional EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, - EDID_BLOCK_LENGTH, - EDID_BLOCK_LENGTH, - &edid[EDID_BLOCK_LENGTH]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } + analogix_dp_send_psr_spd(dp, &psr_vsc); + return 0; +} +EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); - analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, - &test_vector); - if (test_vector & DP_TEST_LINK_EDID_READ) { - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_EDID_CHECKSUM, - edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_RESPONSE, - DP_TEST_EDID_CHECKSUM_WRITE); - } - } else { - dev_info(dp->dev, "EDID data does not include any extensions.\n"); - - /* Read EDID data */ - retval = analogix_dp_read_bytes_from_i2c(dp, - I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, &edid[EDID_HEADER_PATTERN]); - if (retval != 0) { - dev_err(dp->dev, "EDID Read failed!\n"); - return -EIO; - } - sum = analogix_dp_calc_edid_check_sum(edid); - if (sum != 0) { - dev_err(dp->dev, "EDID bad checksum!\n"); - return -EIO; - } +int analogix_dp_disable_psr(struct device *dev) +{ + struct analogix_dp_device *dp = dev_get_drvdata(dev); + struct edp_vsc_psr psr_vsc; - analogix_dp_read_byte_from_dpcd(dp, DP_TEST_REQUEST, - &test_vector); - if (test_vector & DP_TEST_LINK_EDID_READ) { - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_EDID_CHECKSUM, edid[EDID_CHECKSUM]); - analogix_dp_write_byte_to_dpcd(dp, - DP_TEST_RESPONSE, DP_TEST_EDID_CHECKSUM_WRITE); - } - } + if (!dp->psr_support) + return -EINVAL; + + /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ + memset(&psr_vsc, 0, sizeof(psr_vsc)); + psr_vsc.sdp_header.HB0 = 0; + psr_vsc.sdp_header.HB1 = 0x7; + psr_vsc.sdp_header.HB2 = 0x2; + psr_vsc.sdp_header.HB3 = 0x8; + + psr_vsc.DB0 = 0; + psr_vsc.DB1 = 0; - dev_dbg(dp->dev, "EDID Read success!\n"); + analogix_dp_send_psr_spd(dp, &psr_vsc); return 0; } +EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); -static int analogix_dp_handle_edid(struct analogix_dp_device *dp) +static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp) { - u8 buf[12]; - int i; - int retval; + unsigned char psr_version; - /* Read DPCD DP_DPCD_REV~RECEIVE_PORT1_CAP_1 */ - retval = analogix_dp_read_bytes_from_dpcd(dp, DP_DPCD_REV, 12, buf); - if (retval) - return retval; + drm_dp_dpcd_readb(&dp->aux, DP_PSR_SUPPORT, &psr_version); + dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version); - /* Read EDID */ - for (i = 0; i < 3; i++) { - retval = analogix_dp_read_edid(dp); - if (!retval) - break; - } + return (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; +} - return retval; +static void analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) +{ + unsigned char psr_en; + + /* Disable psr function */ + drm_dp_dpcd_readb(&dp->aux, DP_PSR_EN_CFG, &psr_en); + psr_en &= ~DP_PSR_ENABLE; + drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en); + + /* Main-Link transmitter remains active during PSR active states */ + psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION; + drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en); + + /* Enable psr function */ + psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE | + DP_PSR_CRC_VERIFICATION; + drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en); + + analogix_dp_enable_psr_crc(dp); } static void @@ -232,15 +189,15 @@ analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp, { u8 data; - analogix_dp_read_byte_from_dpcd(dp, DP_LANE_COUNT_SET, &data); + drm_dp_dpcd_readb(&dp->aux, DP_LANE_COUNT_SET, &data); if (enable) - analogix_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, - DP_LANE_COUNT_ENHANCED_FRAME_EN | - DPCD_LANE_COUNT_SET(data)); + drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET, + DP_LANE_COUNT_ENHANCED_FRAME_EN | + DPCD_LANE_COUNT_SET(data)); else - analogix_dp_write_byte_to_dpcd(dp, DP_LANE_COUNT_SET, - DPCD_LANE_COUNT_SET(data)); + drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET, + DPCD_LANE_COUNT_SET(data)); } static int analogix_dp_is_enhanced_mode_available(struct analogix_dp_device *dp) @@ -248,7 +205,7 @@ static int analogix_dp_is_enhanced_mode_available(struct analogix_dp_device *dp) u8 data; int retval; - analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); + drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data); retval = DPCD_ENHANCED_FRAME_CAP(data); return retval; @@ -267,8 +224,8 @@ static void analogix_dp_training_pattern_dis(struct analogix_dp_device *dp) { analogix_dp_set_training_pattern(dp, DP_NONE); - analogix_dp_write_byte_to_dpcd(dp, DP_TRAINING_PATTERN_SET, - DP_TRAINING_PATTERN_DISABLE); + drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, + DP_TRAINING_PATTERN_DISABLE); } static void @@ -313,8 +270,8 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp) /* Setup RX configuration */ buf[0] = dp->link_train.link_rate; buf[1] = dp->link_train.lane_count; - retval = analogix_dp_write_bytes_to_dpcd(dp, DP_LINK_BW_SET, 2, buf); - if (retval) + retval = drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, buf, 2); + if (retval < 0) return retval; /* Set TX pre-emphasis to minimum */ @@ -338,20 +295,22 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp) analogix_dp_set_training_pattern(dp, TRAINING_PTN1); /* Set RX training pattern */ - retval = analogix_dp_write_byte_to_dpcd(dp, - DP_TRAINING_PATTERN_SET, - DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_1); - if (retval) + retval = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, + DP_LINK_SCRAMBLING_DISABLE | + DP_TRAINING_PATTERN_1); + if (retval < 0) return retval; for (lane = 0; lane < lane_count; lane++) buf[lane] = DP_TRAIN_PRE_EMPH_LEVEL_0 | DP_TRAIN_VOLTAGE_SWING_LEVEL_0; - retval = analogix_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, - lane_count, buf); + retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, buf, + lane_count); + if (retval < 0) + return retval; - return retval; + return 0; } static unsigned char analogix_dp_get_lane_status(u8 link_status[2], int lane) @@ -503,25 +462,23 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp) lane_count = dp->link_train.lane_count; - retval = analogix_dp_read_bytes_from_dpcd(dp, - DP_LANE0_1_STATUS, 2, link_status); - if (retval) + retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2); + if (retval < 0) return retval; - retval = analogix_dp_read_bytes_from_dpcd(dp, - DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); - if (retval) + retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, + adjust_request, 2); + if (retval < 0) return retval; if (analogix_dp_clock_recovery_ok(link_status, lane_count) == 0) { /* set training pattern 2 for EQ */ analogix_dp_set_training_pattern(dp, TRAINING_PTN2); - retval = analogix_dp_write_byte_to_dpcd(dp, - DP_TRAINING_PATTERN_SET, - DP_LINK_SCRAMBLING_DISABLE | - DP_TRAINING_PATTERN_2); - if (retval) + retval = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, + DP_LINK_SCRAMBLING_DISABLE | + DP_TRAINING_PATTERN_2); + if (retval < 0) return retval; dev_info(dp->dev, "Link Training Clock Recovery success\n"); @@ -559,13 +516,12 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp) analogix_dp_set_lane_link_training(dp, dp->link_train.training_lane[lane], lane); - retval = analogix_dp_write_bytes_to_dpcd(dp, - DP_TRAINING_LANE0_SET, lane_count, - dp->link_train.training_lane); - if (retval) + retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, + dp->link_train.training_lane, lane_count); + if (retval < 0) return retval; - return retval; + return 0; } static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) @@ -578,9 +534,8 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) lane_count = dp->link_train.lane_count; - retval = analogix_dp_read_bytes_from_dpcd(dp, - DP_LANE0_1_STATUS, 2, link_status); - if (retval) + retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2); + if (retval < 0) return retval; if (analogix_dp_clock_recovery_ok(link_status, lane_count)) { @@ -588,14 +543,14 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) return -EIO; } - retval = analogix_dp_read_bytes_from_dpcd(dp, - DP_ADJUST_REQUEST_LANE0_1, 2, adjust_request); - if (retval) + retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, + adjust_request, 2); + if (retval < 0) return retval; - retval = analogix_dp_read_byte_from_dpcd(dp, - DP_LANE_ALIGN_STATUS_UPDATED, &link_align); - if (retval) + retval = drm_dp_dpcd_readb(&dp->aux, DP_LANE_ALIGN_STATUS_UPDATED, + &link_align); + if (retval < 0) return retval; analogix_dp_get_adjust_training_lane(dp, adjust_request); @@ -636,10 +591,12 @@ static int analogix_dp_process_equalizer_training(struct analogix_dp_device *dp) analogix_dp_set_lane_link_training(dp, dp->link_train.training_lane[lane], lane); - retval = analogix_dp_write_bytes_to_dpcd(dp, DP_TRAINING_LANE0_SET, - lane_count, dp->link_train.training_lane); + retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, + dp->link_train.training_lane, lane_count); + if (retval < 0) + return retval; - return retval; + return 0; } static void analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device *dp, @@ -653,7 +610,7 @@ static void analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device *dp, * For DP rev.1.2, Maximum link rate of Main Link lanes * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps, 0x14 = 5.4Gbps */ - analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LINK_RATE, &data); + drm_dp_dpcd_readb(&dp->aux, DP_MAX_LINK_RATE, &data); *bandwidth = data; } @@ -666,7 +623,7 @@ static void analogix_dp_get_max_rx_lane_count(struct analogix_dp_device *dp, * For DP rev.1.1, Maximum number of Main Link lanes * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes */ - analogix_dp_read_byte_from_dpcd(dp, DP_MAX_LANE_COUNT, &data); + drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data); *lane_count = DPCD_MAX_LANE_COUNT(data); } @@ -835,19 +792,15 @@ static void analogix_dp_enable_scramble(struct analogix_dp_device *dp, if (enable) { analogix_dp_enable_scrambling(dp); - analogix_dp_read_byte_from_dpcd(dp, DP_TRAINING_PATTERN_SET, - &data); - analogix_dp_write_byte_to_dpcd(dp, - DP_TRAINING_PATTERN_SET, - (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE)); + drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET, &data); + drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, + (u8)(data & ~DP_LINK_SCRAMBLING_DISABLE)); } else { analogix_dp_disable_scrambling(dp); - analogix_dp_read_byte_from_dpcd(dp, DP_TRAINING_PATTERN_SET, - &data); - analogix_dp_write_byte_to_dpcd(dp, - DP_TRAINING_PATTERN_SET, - (u8)(data | DP_LINK_SCRAMBLING_DISABLE)); + drm_dp_dpcd_readb(&dp->aux, DP_TRAINING_PATTERN_SET, &data); + drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, + (u8)(data | DP_LINK_SCRAMBLING_DISABLE)); } } @@ -921,21 +874,85 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) /* Enable video */ analogix_dp_start_video(dp); + + dp->psr_support = analogix_dp_detect_sink_psr(dp); + if (dp->psr_support) + analogix_dp_enable_sink_psr(dp); } -int analogix_dp_get_modes(struct drm_connector *connector) +/* + * This function is a bit of a catch-all for panel preparation, hopefully + * simplifying the logic of functions that need to prepare/unprepare the panel + * below. + * + * If @prepare is true, this function will prepare the panel. Conversely, if it + * is false, the panel will be unprepared. + * + * If @is_modeset_prepare is true, the function will disregard the current state + * of the panel and either prepare/unprepare the panel based on @prepare. Once + * it finishes, it will update dp->panel_is_modeset to reflect the current state + * of the panel. + */ +static int analogix_dp_prepare_panel(struct analogix_dp_device *dp, + bool prepare, bool is_modeset_prepare) { - struct analogix_dp_device *dp = to_dp(connector); - struct edid *edid = (struct edid *)dp->edid; - int num_modes = 0; + int ret = 0; - if (analogix_dp_handle_edid(dp) == 0) { - drm_mode_connector_update_edid_property(&dp->connector, edid); - num_modes += drm_add_edid_modes(&dp->connector, edid); - } + if (!dp->plat_data->panel) + return 0; - if (dp->plat_data->panel) + mutex_lock(&dp->panel_lock); + + /* + * Exit early if this is a temporary prepare/unprepare and we're already + * modeset (since we neither want to prepare twice or unprepare early). + */ + if (dp->panel_is_modeset && !is_modeset_prepare) + goto out; + + if (prepare) + ret = drm_panel_prepare(dp->plat_data->panel); + else + ret = drm_panel_unprepare(dp->plat_data->panel); + + if (ret) + goto out; + + if (is_modeset_prepare) + dp->panel_is_modeset = prepare; + +out: + mutex_unlock(&dp->panel_lock); + return ret; +} + +static int analogix_dp_get_modes(struct drm_connector *connector) +{ + struct analogix_dp_device *dp = to_dp(connector); + struct edid *edid; + int ret, num_modes = 0; + + if (dp->plat_data->panel) { num_modes += drm_panel_get_modes(dp->plat_data->panel); + } else { + ret = analogix_dp_prepare_panel(dp, true, false); + if (ret) { + DRM_ERROR("Failed to prepare panel (%d)\n", ret); + return 0; + } + + edid = drm_get_edid(connector, &dp->aux.ddc); + if (edid) { + drm_mode_connector_update_edid_property(&dp->connector, + edid); + num_modes += drm_add_edid_modes(&dp->connector, edid); + kfree(edid); + } + + ret = analogix_dp_prepare_panel(dp, false, false); + if (ret) + DRM_ERROR("Failed to unprepare panel (%d)\n", ret); + } if (dp->plat_data->get_modes) num_modes += dp->plat_data->get_modes(dp->plat_data, connector); @@ -956,29 +973,37 @@ static const struct drm_connector_helper_funcs analogix_dp_connector_helper_func .best_encoder = analogix_dp_best_encoder, }; -enum drm_connector_status +static enum drm_connector_status analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); + enum drm_connector_status status = connector_status_disconnected; + int ret; - if (analogix_dp_detect_hpd(dp)) + if (dp->plat_data->panel) + return connector_status_connected; + + ret = analogix_dp_prepare_panel(dp, true, false); + if (ret) { + DRM_ERROR("Failed to prepare panel (%d)\n", ret); return connector_status_disconnected; + } - return connector_status_connected; -} + if (!analogix_dp_detect_hpd(dp)) + status = connector_status_connected; -static void analogix_dp_connector_destroy(struct drm_connector *connector) -{ - drm_connector_unregister(connector); - drm_connector_cleanup(connector); + ret = analogix_dp_prepare_panel(dp, false, false); + if (ret) + DRM_ERROR("Failed to unprepare panel (%d)\n", ret); + return status; } static const struct drm_connector_funcs analogix_dp_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = analogix_dp_detect, - .destroy = analogix_dp_connector_destroy, + .destroy = drm_connector_cleanup, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, @@ -1035,6 +1060,16 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge) return 0; } +static void analogix_dp_bridge_pre_enable(struct drm_bridge *bridge) +{ + struct analogix_dp_device *dp = bridge->driver_private; + int ret; + + ret = analogix_dp_prepare_panel(dp, true, true); + if (ret) + DRM_ERROR("failed to setup the panel ret = %d\n", ret); +} + static void analogix_dp_bridge_enable(struct drm_bridge *bridge) { struct analogix_dp_device *dp = bridge->driver_private; @@ -1058,6 +1093,7 @@ static void analogix_dp_bridge_enable(struct drm_bridge *bridge) static void analogix_dp_bridge_disable(struct drm_bridge *bridge) { struct analogix_dp_device *dp = bridge->driver_private; + int ret; if (dp->dpms_mode != DRM_MODE_DPMS_ON) return; @@ -1077,6 +1113,10 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) pm_runtime_put_sync(dp->dev); + ret = analogix_dp_prepare_panel(dp, false, true); + if (ret) + DRM_ERROR("failed to setup the panel ret = %d\n", ret); + dp->dpms_mode = DRM_MODE_DPMS_OFF; } @@ -1165,9 +1205,9 @@ static void analogix_dp_bridge_nop(struct drm_bridge *bridge) } static const struct drm_bridge_funcs analogix_dp_bridge_funcs = { + .pre_enable = analogix_dp_bridge_pre_enable, .enable = analogix_dp_bridge_enable, .disable = analogix_dp_bridge_disable, - .pre_enable = analogix_dp_bridge_nop, .post_disable = analogix_dp_bridge_nop, .mode_set = analogix_dp_bridge_mode_set, .attach = analogix_dp_bridge_attach, @@ -1231,6 +1271,14 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp) return 0; } +static ssize_t analogix_dpaux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + struct analogix_dp_device *dp = to_dp(aux); + + return analogix_dp_transfer(dp, msg); +} + int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, struct analogix_dp_plat_data *plat_data) { @@ -1254,6 +1302,9 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, dp->dev = &pdev->dev; dp->dpms_mode = DRM_MODE_DPMS_OFF; + mutex_init(&dp->panel_lock); + dp->panel_is_modeset = false; + /* * platform dp driver need containor_of the plat_data to get * the driver private data, so we need to store the point of @@ -1333,13 +1384,6 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, phy_power_on(dp->phy); - if (dp->plat_data->panel) { - if (drm_panel_prepare(dp->plat_data->panel)) { - DRM_ERROR("failed to setup the panel\n"); - return -EBUSY; - } - } - analogix_dp_init_dp(dp); ret = devm_request_threaded_irq(&pdev->dev, dp->irq, @@ -1355,6 +1399,14 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, dp->drm_dev = drm_dev; dp->encoder = dp->plat_data->encoder; + dp->aux.name = "DP-AUX"; + dp->aux.transfer = analogix_dpaux_transfer; + dp->aux.dev = &pdev->dev; + + ret = drm_dp_aux_register(&dp->aux); + if (ret) + goto err_disable_pm_runtime; + ret = analogix_dp_create_bridge(drm_dev, dp); if (ret) { DRM_ERROR("failed to create bridge (%d)\n", ret); diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index b45638043ec4..5c6a28806129 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -20,15 +20,6 @@ #define MAX_CR_LOOP 5 #define MAX_EQ_LOOP 5 -/* I2C EDID Chip ID, Slave Address */ -#define I2C_EDID_DEVICE_ADDR 0x50 -#define I2C_E_EDID_DEVICE_ADDR 0x30 - -#define EDID_BLOCK_LENGTH 0x80 -#define EDID_HEADER_PATTERN 0x00 -#define EDID_EXTENSION_FLAG 0x7e -#define EDID_CHECKSUM 0x7f - /* DP_MAX_LANE_COUNT */ #define DPCD_ENHANCED_FRAME_CAP(x) (((x) >> 7) & 0x1) #define DPCD_MAX_LANE_COUNT(x) ((x) & 0x1f) @@ -166,6 +157,7 @@ struct analogix_dp_device { struct drm_device *drm_dev; struct drm_connector connector; struct drm_bridge *bridge; + struct drm_dp_aux aux; struct clk *clock; unsigned int irq; void __iomem *reg_base; @@ -176,7 +168,10 @@ struct analogix_dp_device { int dpms_mode; int hpd_gpio; bool force_hpd; - unsigned char edid[EDID_BLOCK_LENGTH * 2]; + bool psr_support; + + struct mutex panel_lock; + bool panel_is_modeset; struct analogix_dp_plat_data *plat_data; }; @@ -206,33 +201,6 @@ void analogix_dp_reset_aux(struct analogix_dp_device *dp); void analogix_dp_init_aux(struct analogix_dp_device *dp); int analogix_dp_get_plug_in_status(struct analogix_dp_device *dp); void analogix_dp_enable_sw_function(struct analogix_dp_device *dp); -int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp); -int analogix_dp_write_byte_to_dpcd(struct analogix_dp_device *dp, - unsigned int reg_addr, - unsigned char data); -int analogix_dp_read_byte_from_dpcd(struct analogix_dp_device *dp, - unsigned int reg_addr, - unsigned char *data); -int analogix_dp_write_bytes_to_dpcd(struct analogix_dp_device *dp, - unsigned int reg_addr, - unsigned int count, - unsigned char data[]); -int analogix_dp_read_bytes_from_dpcd(struct analogix_dp_device *dp, - unsigned int reg_addr, - unsigned int count, - unsigned char data[]); -int analogix_dp_select_i2c_device(struct analogix_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr); -int analogix_dp_read_byte_from_i2c(struct analogix_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr, - unsigned int *data); -int analogix_dp_read_bytes_from_i2c(struct analogix_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr, - unsigned int count, - unsigned char edid[]); void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype); void analogix_dp_get_link_bandwidth(struct analogix_dp_device *dp, u32 *bwtype); void analogix_dp_set_lane_count(struct analogix_dp_device *dp, u32 count); @@ -278,4 +246,10 @@ int analogix_dp_is_video_stream_on(struct analogix_dp_device *dp); void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp); void analogix_dp_enable_scrambling(struct analogix_dp_device *dp); void analogix_dp_disable_scrambling(struct analogix_dp_device *dp); +void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp); +void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, + struct edp_vsc_psr *vsc); +ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, + struct drm_dp_aux_msg *msg); + #endif /* _ANALOGIX_DP_CORE_H */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c index 48030f0cf497..cd37ac058675 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c @@ -585,330 +585,6 @@ int analogix_dp_write_byte_to_dpcd(struct analogix_dp_device *dp, return retval; } -int analogix_dp_read_byte_from_dpcd(struct analogix_dp_device *dp, - unsigned int reg_addr, - unsigned char *data) -{ - u32 reg; - int i; - int retval; - - for (i = 0; i < 3; i++) { - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); - - /* Select DPCD device address */ - reg = AUX_ADDR_7_0(reg_addr); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); - reg = AUX_ADDR_15_8(reg_addr); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); - reg = AUX_ADDR_19_16(reg_addr); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); - - /* - * Set DisplayPort transaction and read 1 byte - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = analogix_dp_start_aux_transaction(dp); - if (retval == 0) - break; - - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); - } - - /* Read data buffer */ - reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0); - *data = (unsigned char)(reg & 0xff); - - return retval; -} - -int analogix_dp_write_bytes_to_dpcd(struct analogix_dp_device *dp, - unsigned int reg_addr, - unsigned int count, - unsigned char data[]) -{ - u32 reg; - unsigned int start_offset; - unsigned int cur_data_count; - unsigned int cur_data_idx; - int i; - int retval = 0; - - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); - - start_offset = 0; - while (start_offset < count) { - /* Buffer size of AUX CH is 16 * 4bytes */ - if ((count - start_offset) > 16) - cur_data_count = 16; - else - cur_data_count = count - start_offset; - - for (i = 0; i < 3; i++) { - /* Select DPCD device address */ - reg = AUX_ADDR_7_0(reg_addr + start_offset); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); - reg = AUX_ADDR_15_8(reg_addr + start_offset); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); - reg = AUX_ADDR_19_16(reg_addr + start_offset); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); - - for (cur_data_idx = 0; cur_data_idx < cur_data_count; - cur_data_idx++) { - reg = data[start_offset + cur_data_idx]; - writel(reg, dp->reg_base + - ANALOGIX_DP_BUF_DATA_0 + - 4 * cur_data_idx); - } - - /* - * Set DisplayPort transaction and write - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_LENGTH(cur_data_count) | - AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = analogix_dp_start_aux_transaction(dp); - if (retval == 0) - break; - - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", - __func__); - } - - start_offset += cur_data_count; - } - - return retval; -} - -int analogix_dp_read_bytes_from_dpcd(struct analogix_dp_device *dp, - unsigned int reg_addr, - unsigned int count, - unsigned char data[]) -{ - u32 reg; - unsigned int start_offset; - unsigned int cur_data_count; - unsigned int cur_data_idx; - int i; - int retval = 0; - - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); - - start_offset = 0; - while (start_offset < count) { - /* Buffer size of AUX CH is 16 * 4bytes */ - if ((count - start_offset) > 16) - cur_data_count = 16; - else - cur_data_count = count - start_offset; - - /* AUX CH Request Transaction process */ - for (i = 0; i < 3; i++) { - /* Select DPCD device address */ - reg = AUX_ADDR_7_0(reg_addr + start_offset); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); - reg = AUX_ADDR_15_8(reg_addr + start_offset); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); - reg = AUX_ADDR_19_16(reg_addr + start_offset); - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); - - /* - * Set DisplayPort transaction and read - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_LENGTH(cur_data_count) | - AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = analogix_dp_start_aux_transaction(dp); - if (retval == 0) - break; - - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", - __func__); - } - - for (cur_data_idx = 0; cur_data_idx < cur_data_count; - cur_data_idx++) { - reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0 - + 4 * cur_data_idx); - data[start_offset + cur_data_idx] = - (unsigned char)reg; - } - - start_offset += cur_data_count; - } - - return retval; -} - -int analogix_dp_select_i2c_device(struct analogix_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr) -{ - u32 reg; - int retval; - - /* Set EDID device address */ - reg = device_addr; - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); - writel(0x0, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); - writel(0x0, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); - - /* Set offset from base address of EDID device */ - writel(reg_addr, dp->reg_base + ANALOGIX_DP_BUF_DATA_0); - - /* - * Set I2C transaction and write address - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT | - AUX_TX_COMM_WRITE; - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = analogix_dp_start_aux_transaction(dp); - if (retval != 0) - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); - - return retval; -} - -int analogix_dp_read_byte_from_i2c(struct analogix_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr, - unsigned int *data) -{ - u32 reg; - int i; - int retval; - - for (i = 0; i < 3; i++) { - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); - - /* Select EDID device */ - retval = analogix_dp_select_i2c_device(dp, device_addr, - reg_addr); - if (retval != 0) - continue; - - /* - * Set I2C transaction and read data - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_TX_COMM_I2C_TRANSACTION | - AUX_TX_COMM_READ; - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = analogix_dp_start_aux_transaction(dp); - if (retval == 0) - break; - - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__); - } - - /* Read data */ - if (retval == 0) - *data = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0); - - return retval; -} - -int analogix_dp_read_bytes_from_i2c(struct analogix_dp_device *dp, - unsigned int device_addr, - unsigned int reg_addr, - unsigned int count, - unsigned char edid[]) -{ - u32 reg; - unsigned int i, j; - unsigned int cur_data_idx; - unsigned int defer = 0; - int retval = 0; - - for (i = 0; i < count; i += 16) { - for (j = 0; j < 3; j++) { - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); - - /* Set normal AUX CH command */ - reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); - reg &= ~ADDR_ONLY; - writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); - - /* - * If Rx sends defer, Tx sends only reads - * request without sending address - */ - if (!defer) - retval = analogix_dp_select_i2c_device(dp, - device_addr, reg_addr + i); - else - defer = 0; - - if (retval == 0) { - /* - * Set I2C transaction and write data - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_LENGTH(16) | - AUX_TX_COMM_I2C_TRANSACTION | - AUX_TX_COMM_READ; - writel(reg, dp->reg_base + - ANALOGIX_DP_AUX_CH_CTL_1); - - /* Start AUX transaction */ - retval = analogix_dp_start_aux_transaction(dp); - if (retval == 0) - break; - - dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", - __func__); - } - /* Check if Rx sends defer */ - reg = readl(dp->reg_base + ANALOGIX_DP_AUX_RX_COMM); - if (reg == AUX_RX_COMM_AUX_DEFER || - reg == AUX_RX_COMM_I2C_DEFER) { - dev_err(dp->dev, "Defer: %d\n\n", reg); - defer = 1; - } - } - - for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) { - reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0 - + 4 * cur_data_idx); - edid[i + cur_data_idx] = (unsigned char)reg; - } - } - - return retval; -} - void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype) { u32 reg; @@ -1073,34 +749,22 @@ void analogix_dp_set_lane3_link_training(struct analogix_dp_device *dp, u32 analogix_dp_get_lane0_link_training(struct analogix_dp_device *dp) { - u32 reg; - - reg = readl(dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); - return reg; + return readl(dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); } u32 analogix_dp_get_lane1_link_training(struct analogix_dp_device *dp) { - u32 reg; - - reg = readl(dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); - return reg; + return readl(dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); } u32 analogix_dp_get_lane2_link_training(struct analogix_dp_device *dp) { - u32 reg; - - reg = readl(dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); - return reg; + return readl(dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); } u32 analogix_dp_get_lane3_link_training(struct analogix_dp_device *dp) { - u32 reg; - - reg = readl(dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); - return reg; + return readl(dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); } void analogix_dp_reset_macro(struct analogix_dp_device *dp) @@ -1322,3 +986,181 @@ void analogix_dp_disable_scrambling(struct analogix_dp_device *dp) reg |= SCRAMBLING_DISABLE; writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); } + +void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) +{ + writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON); +} + +void analogix_dp_send_psr_spd(struct analogix_dp_device *dp, + struct edp_vsc_psr *vsc) +{ + unsigned int val; + + /* don't send info frame */ + val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + val &= ~IF_EN; + writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + + /* configure single frame update mode */ + writel(PSR_FRAME_UP_TYPE_BURST | PSR_CRC_SEL_HARDWARE, + dp->reg_base + ANALOGIX_DP_PSR_FRAME_UPDATE_CTRL); + + /* configure VSC HB0~HB3 */ + writel(vsc->sdp_header.HB0, dp->reg_base + ANALOGIX_DP_SPD_HB0); + writel(vsc->sdp_header.HB1, dp->reg_base + ANALOGIX_DP_SPD_HB1); + writel(vsc->sdp_header.HB2, dp->reg_base + ANALOGIX_DP_SPD_HB2); + writel(vsc->sdp_header.HB3, dp->reg_base + ANALOGIX_DP_SPD_HB3); + + /* configure reused VSC PB0~PB3, magic number from vendor */ + writel(0x00, dp->reg_base + ANALOGIX_DP_SPD_PB0); + writel(0x16, dp->reg_base + ANALOGIX_DP_SPD_PB1); + writel(0xCE, dp->reg_base + ANALOGIX_DP_SPD_PB2); + writel(0x5D, dp->reg_base + ANALOGIX_DP_SPD_PB3); + + /* configure DB0 / DB1 values */ + writel(vsc->DB0, dp->reg_base + ANALOGIX_DP_VSC_SHADOW_DB0); + writel(vsc->DB1, dp->reg_base + ANALOGIX_DP_VSC_SHADOW_DB1); + + /* set reuse spd inforframe */ + val = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3); + val |= REUSE_SPD_EN; + writel(val, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3); + + /* mark info frame update */ + val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + val = (val | IF_UP) & ~IF_EN; + writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + + /* send info frame */ + val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); + val |= IF_EN; + writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); +} + +ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, + struct drm_dp_aux_msg *msg) +{ + u32 reg; + u8 *buffer = msg->buffer; + int timeout_loop = 0; + unsigned int i; + int num_transferred = 0; + + /* Buffer size of AUX CH is 16 bytes */ + if (WARN_ON(msg->size > 16)) + return -E2BIG; + + /* Clear AUX CH data buffer */ + reg = BUF_CLR; + writel(reg, dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_I2C_WRITE: + reg = AUX_TX_COMM_WRITE | AUX_TX_COMM_I2C_TRANSACTION; + if (msg->request & DP_AUX_I2C_MOT) + reg |= AUX_TX_COMM_MOT; + break; + + case DP_AUX_I2C_READ: + reg = AUX_TX_COMM_READ | AUX_TX_COMM_I2C_TRANSACTION; + if (msg->request & DP_AUX_I2C_MOT) + reg |= AUX_TX_COMM_MOT; + break; + + case DP_AUX_NATIVE_WRITE: + reg = AUX_TX_COMM_WRITE | AUX_TX_COMM_DP_TRANSACTION; + break; + + case DP_AUX_NATIVE_READ: + reg = AUX_TX_COMM_READ | AUX_TX_COMM_DP_TRANSACTION; + break; + + default: + return -EINVAL; + } + + reg |= AUX_LENGTH(msg->size); + writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); + + /* Select DPCD device address */ + reg = AUX_ADDR_7_0(msg->address); + writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); + reg = AUX_ADDR_15_8(msg->address); + writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); + reg = AUX_ADDR_19_16(msg->address); + writel(reg, dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); + + if (!(msg->request & DP_AUX_I2C_READ)) { + for (i = 0; i < msg->size; i++) { + reg = buffer[i]; + writel(reg, dp->reg_base + ANALOGIX_DP_BUF_DATA_0 + + 4 * i); + num_transferred++; + } + } + + /* Enable AUX CH operation */ + reg = AUX_EN; + + /* Zero-sized messages specify address-only transactions. */ + if (msg->size < 1) + reg |= ADDR_ONLY; + + writel(reg, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); + + /* Is AUX CH command reply received? */ + /* TODO: Wait for an interrupt instead of looping? */ + reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); + while (!(reg & RPLY_RECEIV)) { + timeout_loop++; + if (timeout_loop > DP_TIMEOUT_LOOP_COUNT) { + dev_err(dp->dev, "AUX CH command reply failed!\n"); + return -ETIMEDOUT; + } + reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); + usleep_range(10, 11); + } + + /* Clear interrupt source for AUX CH command reply */ + writel(RPLY_RECEIV, dp->reg_base + ANALOGIX_DP_INT_STA); + + /* Clear interrupt source for AUX CH access error */ + reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA); + if (reg & AUX_ERR) { + writel(AUX_ERR, dp->reg_base + ANALOGIX_DP_INT_STA); + return -EREMOTEIO; + } + + /* Check AUX CH error access status */ + reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_STA); + if ((reg & AUX_STATUS_MASK)) { + dev_err(dp->dev, "AUX CH error happened: %d\n\n", + reg & AUX_STATUS_MASK); + return -EREMOTEIO; + } + + if (msg->request & DP_AUX_I2C_READ) { + for (i = 0; i < msg->size; i++) { + reg = readl(dp->reg_base + ANALOGIX_DP_BUF_DATA_0 + + 4 * i); + buffer[i] = (unsigned char)reg; + num_transferred++; + } + } + + /* Check if Rx sends defer */ + reg = readl(dp->reg_base + ANALOGIX_DP_AUX_RX_COMM); + if (reg == AUX_RX_COMM_AUX_DEFER) + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + else if (reg == AUX_RX_COMM_I2C_DEFER) + msg->reply = DP_AUX_I2C_REPLY_DEFER; + else if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_WRITE || + (msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_READ) + msg->reply = DP_AUX_I2C_REPLY_ACK; + else if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_WRITE || + (msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_READ) + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + + return num_transferred; +} diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h index cdcc6c5add5e..40200c652533 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h @@ -22,6 +22,8 @@ #define ANALOGIX_DP_VIDEO_CTL_8 0x3C #define ANALOGIX_DP_VIDEO_CTL_10 0x44 +#define ANALOGIX_DP_SPDIF_AUDIO_CTL_0 0xD8 + #define ANALOGIX_DP_PLL_REG_1 0xfc #define ANALOGIX_DP_PLL_REG_2 0x9e4 #define ANALOGIX_DP_PLL_REG_3 0x9e8 @@ -30,6 +32,21 @@ #define ANALOGIX_DP_PD 0x12c +#define ANALOGIX_DP_IF_TYPE 0x244 +#define ANALOGIX_DP_IF_PKT_DB1 0x254 +#define ANALOGIX_DP_IF_PKT_DB2 0x258 +#define ANALOGIX_DP_SPD_HB0 0x2F8 +#define ANALOGIX_DP_SPD_HB1 0x2FC +#define ANALOGIX_DP_SPD_HB2 0x300 +#define ANALOGIX_DP_SPD_HB3 0x304 +#define ANALOGIX_DP_SPD_PB0 0x308 +#define ANALOGIX_DP_SPD_PB1 0x30C +#define ANALOGIX_DP_SPD_PB2 0x310 +#define ANALOGIX_DP_SPD_PB3 0x314 +#define ANALOGIX_DP_PSR_FRAME_UPDATE_CTRL 0x318 +#define ANALOGIX_DP_VSC_SHADOW_DB0 0x31C +#define ANALOGIX_DP_VSC_SHADOW_DB1 0x320 + #define ANALOGIX_DP_LANE_MAP 0x35C #define ANALOGIX_DP_ANALOG_CTL_1 0x370 @@ -103,6 +120,8 @@ #define ANALOGIX_DP_SOC_GENERAL_CTL 0x800 +#define ANALOGIX_DP_CRC_CON 0x890 + /* ANALOGIX_DP_TX_SW_RESET */ #define RESET_DP_TX (0x1 << 0) @@ -151,6 +170,7 @@ #define VID_CHK_UPDATE_TYPE_SHIFT (4) #define VID_CHK_UPDATE_TYPE_1 (0x1 << 4) #define VID_CHK_UPDATE_TYPE_0 (0x0 << 4) +#define REUSE_SPD_EN (0x1 << 3) /* ANALOGIX_DP_VIDEO_CTL_8 */ #define VID_HRES_TH(x) (((x) & 0xf) << 4) @@ -167,6 +187,12 @@ #define REF_CLK_27M (0x0 << 0) #define REF_CLK_MASK (0x1 << 0) +/* ANALOGIX_DP_PSR_FRAME_UPDATE_CTRL */ +#define PSR_FRAME_UP_TYPE_BURST (0x1 << 0) +#define PSR_FRAME_UP_TYPE_SINGLE (0x0 << 0) +#define PSR_CRC_SEL_HARDWARE (0x1 << 1) +#define PSR_CRC_SEL_MANUALLY (0x0 << 1) + /* ANALOGIX_DP_LANE_MAP */ #define LANE3_MAP_LOGIC_LANE_0 (0x0 << 6) #define LANE3_MAP_LOGIC_LANE_1 (0x1 << 6) @@ -376,4 +402,12 @@ #define VIDEO_MODE_SLAVE_MODE (0x1 << 0) #define VIDEO_MODE_MASTER_MODE (0x0 << 0) +/* ANALOGIX_DP_PKT_SEND_CTL */ +#define IF_UP (0x1 << 4) +#define IF_EN (0x1 << 0) + +/* ANALOGIX_DP_CRC_CON */ +#define PSR_VID_CRC_FLUSH (0x1 << 2) +#define PSR_VID_CRC_ENABLE (0x1 << 0) + #endif /* _ANALOGIX_DP_REG_H */ diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c new file mode 100644 index 000000000000..afec232185a7 --- /dev/null +++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2015-2016 Free Electrons + * Copyright (C) 2015-2016 NextThing Co + * + * Maxime Ripard <maxime.ripard@free-electrons.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/of_graph.h> + +#include <drm/drmP.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> + +struct dumb_vga { + struct drm_bridge bridge; + struct drm_connector connector; + + struct i2c_adapter *ddc; +}; + +static inline struct dumb_vga * +drm_bridge_to_dumb_vga(struct drm_bridge *bridge) +{ + return container_of(bridge, struct dumb_vga, bridge); +} + +static inline struct dumb_vga * +drm_connector_to_dumb_vga(struct drm_connector *connector) +{ + return container_of(connector, struct dumb_vga, connector); +} + +static int dumb_vga_get_modes(struct drm_connector *connector) +{ + struct dumb_vga *vga = drm_connector_to_dumb_vga(connector); + struct edid *edid; + int ret; + + if (IS_ERR(vga->ddc)) + goto fallback; + + edid = drm_get_edid(connector, vga->ddc); + if (!edid) { + DRM_INFO("EDID readout failed, falling back to standard modes\n"); + goto fallback; + } + + drm_mode_connector_update_edid_property(connector, edid); + return drm_add_edid_modes(connector, edid); + +fallback: + /* + * In case we cannot retrieve the EDIDs (broken or missing i2c + * bus), fallback on the XGA standards + */ + ret = drm_add_modes_noedid(connector, 1920, 1200); + + /* And prefer a mode pretty much anyone can handle */ + drm_set_preferred_mode(connector, 1024, 768); + + return ret; +} + +static const struct drm_connector_helper_funcs dumb_vga_con_helper_funcs = { + .get_modes = dumb_vga_get_modes, +}; + +static enum drm_connector_status +dumb_vga_connector_detect(struct drm_connector *connector, bool force) +{ + struct dumb_vga *vga = drm_connector_to_dumb_vga(connector); + + /* + * Even if we have an I2C bus, we can't assume that the cable + * is disconnected if drm_probe_ddc fails. Some cables don't + * wire the DDC pins, or the I2C bus might not be working at + * all. + */ + if (!IS_ERR(vga->ddc) && drm_probe_ddc(vga->ddc)) + return connector_status_connected; + + return connector_status_unknown; +} + +static const struct drm_connector_funcs dumb_vga_con_funcs = { + .dpms = drm_atomic_helper_connector_dpms, + .detect = dumb_vga_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int dumb_vga_attach(struct drm_bridge *bridge) +{ + struct dumb_vga *vga = drm_bridge_to_dumb_vga(bridge); + int ret; + + if (!bridge->encoder) { + DRM_ERROR("Missing encoder\n"); + return -ENODEV; + } + + drm_connector_helper_add(&vga->connector, + &dumb_vga_con_helper_funcs); + ret = drm_connector_init(bridge->dev, &vga->connector, + &dumb_vga_con_funcs, DRM_MODE_CONNECTOR_VGA); + if (ret) { + DRM_ERROR("Failed to initialize connector\n"); + return ret; + } + + drm_mode_connector_attach_encoder(&vga->connector, + bridge->encoder); + + return 0; +} + +static const struct drm_bridge_funcs dumb_vga_bridge_funcs = { + .attach = dumb_vga_attach, +}; + +static struct i2c_adapter *dumb_vga_retrieve_ddc(struct device *dev) +{ + struct device_node *end_node, *phandle, *remote; + struct i2c_adapter *ddc; + + end_node = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1); + if (!end_node) { + dev_err(dev, "Missing connector endpoint\n"); + return ERR_PTR(-ENODEV); + } + + remote = of_graph_get_remote_port_parent(end_node); + of_node_put(end_node); + if (!remote) { + dev_err(dev, "Enable to parse remote node\n"); + return ERR_PTR(-EINVAL); + } + + phandle = of_parse_phandle(remote, "ddc-i2c-bus", 0); + of_node_put(remote); + if (!phandle) + return ERR_PTR(-ENODEV); + + ddc = of_get_i2c_adapter_by_node(phandle); + of_node_put(phandle); + if (!ddc) + return ERR_PTR(-EPROBE_DEFER); + + return ddc; +} + +static int dumb_vga_probe(struct platform_device *pdev) +{ + struct dumb_vga *vga; + int ret; + + vga = devm_kzalloc(&pdev->dev, sizeof(*vga), GFP_KERNEL); + if (!vga) + return -ENOMEM; + platform_set_drvdata(pdev, vga); + + vga->ddc = dumb_vga_retrieve_ddc(&pdev->dev); + if (IS_ERR(vga->ddc)) { + if (PTR_ERR(vga->ddc) == -ENODEV) { + dev_dbg(&pdev->dev, + "No i2c bus specified. Disabling EDID readout\n"); + } else { + dev_err(&pdev->dev, "Couldn't retrieve i2c bus\n"); + return PTR_ERR(vga->ddc); + } + } + + vga->bridge.funcs = &dumb_vga_bridge_funcs; + vga->bridge.of_node = pdev->dev.of_node; + + ret = drm_bridge_add(&vga->bridge); + if (ret && !IS_ERR(vga->ddc)) + i2c_put_adapter(vga->ddc); + + return ret; +} + +static int dumb_vga_remove(struct platform_device *pdev) +{ + struct dumb_vga *vga = platform_get_drvdata(pdev); + + drm_bridge_remove(&vga->bridge); + + if (!IS_ERR(vga->ddc)) + i2c_put_adapter(vga->ddc); + + return 0; +} + +static const struct of_device_id dumb_vga_match[] = { + { .compatible = "dumb-vga-dac" }, + {}, +}; +MODULE_DEVICE_TABLE(of, dumb_vga_match); + +static struct platform_driver dumb_vga_driver = { + .probe = dumb_vga_probe, + .remove = dumb_vga_remove, + .driver = { + .name = "dumb-vga-dac", + .of_match_table = dumb_vga_match, + }, +}; +module_platform_driver(dumb_vga_driver); + +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); +MODULE_DESCRIPTION("Dumb VGA DAC bridge driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/bridge/dw-hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/dw-hdmi-ahb-audio.c index 122bb015f4a9..8f2d1379c880 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi-ahb-audio.c +++ b/drivers/gpu/drm/bridge/dw-hdmi-ahb-audio.c @@ -640,7 +640,6 @@ static struct platform_driver snd_dw_hdmi_driver = { .remove = snd_dw_hdmi_remove, .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .pm = PM_OPS, }, }; diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 77ab47341658..ab7023e5dfde 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -940,10 +940,11 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) */ /* - * AVI data byte 1 differences: Colorspace in bits 4,5 rather than 5,6, - * active aspect present in bit 6 rather than 4. + * AVI data byte 1 differences: Colorspace in bits 0,1 rather than 5,6, + * scan info in bits 4,5 rather than 0,1 and active aspect present in + * bit 6 rather than 4. */ - val = (frame.colorspace & 3) << 4 | (frame.scan_mode & 0x3); + val = (frame.scan_mode & 3) << 4 | (frame.colorspace & 3); if (frame.active_aspect & 15) val |= HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT; if (frame.top_bar || frame.bottom_bar) @@ -1476,12 +1477,6 @@ dw_hdmi_connector_mode_valid(struct drm_connector *connector, return mode_status; } -static void dw_hdmi_connector_destroy(struct drm_connector *connector) -{ - drm_connector_unregister(connector); - drm_connector_cleanup(connector); -} - static void dw_hdmi_connector_force(struct drm_connector *connector) { struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, @@ -1498,7 +1493,7 @@ static const struct drm_connector_funcs dw_hdmi_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = dw_hdmi_connector_detect, - .destroy = dw_hdmi_connector_destroy, + .destroy = drm_connector_cleanup, .force = dw_hdmi_connector_force, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, @@ -1812,9 +1807,6 @@ void dw_hdmi_unbind(struct device *dev, struct device *master, void *data) /* Disable all interrupts */ hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0); - hdmi->connector.funcs->destroy(&hdmi->connector); - hdmi->encoder->funcs->destroy(hdmi->encoder); - clk_disable_unprepare(hdmi->iahb_clk); clk_disable_unprepare(hdmi->isfr_clk); i2c_put_adapter(hdmi->ddc); diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index 93f3dacf9e27..f1a99938e924 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -245,16 +245,11 @@ static enum drm_connector_status ptn3460_detect(struct drm_connector *connector, return connector_status_connected; } -static void ptn3460_connector_destroy(struct drm_connector *connector) -{ - drm_connector_cleanup(connector); -} - static const struct drm_connector_funcs ptn3460_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = ptn3460_detect, - .destroy = ptn3460_connector_destroy, + .destroy = drm_connector_cleanup, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c index 583b8ce614e3..6f7c2f9860d2 100644 --- a/drivers/gpu/drm/bridge/parade-ps8622.c +++ b/drivers/gpu/drm/bridge/parade-ps8622.c @@ -16,7 +16,6 @@ #include <linux/backlight.h> #include <linux/delay.h> #include <linux/err.h> -#include <linux/fb.h> #include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/i2c.h> @@ -484,16 +483,11 @@ static enum drm_connector_status ps8622_detect(struct drm_connector *connector, return connector_status_connected; } -static void ps8622_connector_destroy(struct drm_connector *connector) -{ - drm_connector_cleanup(connector); -} - static const struct drm_connector_funcs ps8622_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = ps8622_detect, - .destroy = ps8622_connector_destroy, + .destroy = drm_connector_cleanup, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index a09825d8c94a..44d476ea6d2e 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1165,17 +1165,11 @@ static const struct drm_connector_helper_funcs tc_connector_helper_funcs = { .best_encoder = tc_connector_best_encoder, }; -static void tc_connector_destroy(struct drm_connector *connector) -{ - drm_connector_unregister(connector); - drm_connector_cleanup(connector); -} - static const struct drm_connector_funcs tc_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = tc_connector_detect, - .destroy = tc_connector_destroy, + .destroy = drm_connector_cleanup, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |