Message ID | 1470401943-28511-1-git-send-email-tomeu.vizoso@collabora.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Fri, Aug 5, 2016 at 8:59 AM, Tomeu Vizoso <tomeu.vizoso@collabora.com> wrote: > Remove code for reading the EDID and DPCD fields and use the helpers > instead. > > Besides the obvious code reduction, other helpers are being added to the > core that could be used in this driver and will be good to be able to > use them instead of duplicating them. > > Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com> > Tested-by: Javier Martinez Canillas <javier@osg.samsung.com> > Tested-by: Sean Paul <seanpaul@chromium.org> > Cc: Javier Martinez Canillas <javier@osg.samsung.com> > Cc: Mika Kahola <mika.kahola@intel.com> > Cc: Yakir Yang <ykk@rock-chips.com> > Cc: Daniel Vetter <daniel.vetter@intel.com> > Thanks for the respin. Reviewed-by: Sean Paul <seanpaul@chromium.org> > v2: > - A bunch of good fixes from Sean and Yakir > - Moved the transfer function to analogix_dp_reg.c > - Removed reference to the EDID from the dp struct > --- > drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 263 ++++-------- > drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 40 +- > drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 451 ++++++--------------- > 3 files changed, 204 insertions(+), 550 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > index 32715daf73cb..624fc4f44450 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,150 +98,21 @@ 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 i; > - unsigned char sum = 0; > - > - for (i = 0; i < EDID_BLOCK_LENGTH; i++) > - sum = sum + edid_data[i]; > - > - return sum; > -} > - > -static int analogix_dp_read_edid(struct analogix_dp_device *dp) > -{ > - unsigned char *edid = dp->edid; > - unsigned int extend_block = 0; > - unsigned char sum; > - unsigned char test_vector; > - int retval; > - > - /* > - * EDID device address is 0x50. > - * However, if necessary, you must have set upper address > - * into E-EDID in I2C device, 0x30. > - */ > - > - /* 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; > - > - 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; > - } > - > - /* 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_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; > - } > - > - 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); > - } > - } > - > - dev_dbg(dp->dev, "EDID Read success!\n"); > - return 0; > -} > - > -static int analogix_dp_handle_edid(struct analogix_dp_device *dp) > -{ > - u8 buf[12]; > - int i; > - int retval; > - > - /* 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; > - > - /* Read EDID */ > - for (i = 0; i < 3; i++) { > - retval = analogix_dp_read_edid(dp); > - if (!retval) > - break; > - } > - > - return retval; > -} > - > static void > analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp, > bool enable) > { > 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 +120,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 +139,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 +185,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 +210,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 +377,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 +431,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 +449,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 +458,13 @@ 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 +505,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 +524,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 +537,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 +706,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)); > } > } > > @@ -926,12 +793,14 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) > int analogix_dp_get_modes(struct drm_connector *connector) > { > struct analogix_dp_device *dp = to_dp(connector); > - struct edid *edid = (struct edid *)dp->edid; > + struct edid *edid; > int num_modes = 0; > > - if (analogix_dp_handle_edid(dp) == 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); > } > > if (dp->plat_data->panel) > @@ -1231,6 +1100,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) > { > @@ -1355,6 +1232,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..3da338cd3178 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,6 @@ struct analogix_dp_device { > int dpms_mode; > int hpd_gpio; > bool force_hpd; > - unsigned char edid[EDID_BLOCK_LENGTH * 2]; > > struct analogix_dp_plat_data *plat_data; > }; > @@ -206,33 +197,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 +242,6 @@ 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); > +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..7ac4caa6bc1c 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; > @@ -1322,3 +998,130 @@ void analogix_dp_disable_scrambling(struct analogix_dp_device *dp) > reg |= SCRAMBLING_DISABLE; > writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); > } > + > +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; > +} > -- > 2.7.4 > > _______________________________________________ > dri-devel mailing list > dri-devel@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/dri-devel
+ Archit Tomeu, Thanks for the update :-) But you have missed three tiny align problems, please see my inline notes, wish you could fix them. After that this patch looks good to me, so: Reviewed-by: Yakir Yang <ykk@rock-chips.com> I guess this patch should go through Archit's drm_bridge tree, so I added him into the CC list. - Yakir On 08/05/2016 08:59 PM, Tomeu Vizoso wrote: > Remove code for reading the EDID and DPCD fields and use the helpers > instead. > > Besides the obvious code reduction, other helpers are being added to the > core that could be used in this driver and will be good to be able to > use them instead of duplicating them. > > Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com> > Tested-by: Javier Martinez Canillas <javier@osg.samsung.com> > Tested-by: Sean Paul <seanpaul@chromium.org> > Cc: Javier Martinez Canillas <javier@osg.samsung.com> > Cc: Mika Kahola <mika.kahola@intel.com> > Cc: Yakir Yang <ykk@rock-chips.com> > Cc: Daniel Vetter <daniel.vetter@intel.com> > > v2: > - A bunch of good fixes from Sean and Yakir > - Moved the transfer function to analogix_dp_reg.c > - Removed reference to the EDID from the dp struct > --- > drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 263 ++++-------- > drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 40 +- > drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 451 ++++++--------------- > 3 files changed, 204 insertions(+), 550 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c > index 32715daf73cb..624fc4f44450 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,150 +98,21 @@ 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 i; > - unsigned char sum = 0; > - > - for (i = 0; i < EDID_BLOCK_LENGTH; i++) > - sum = sum + edid_data[i]; > - > - return sum; > -} > - > -static int analogix_dp_read_edid(struct analogix_dp_device *dp) > -{ > - unsigned char *edid = dp->edid; > - unsigned int extend_block = 0; > - unsigned char sum; > - unsigned char test_vector; > - int retval; > - > - /* > - * EDID device address is 0x50. > - * However, if necessary, you must have set upper address > - * into E-EDID in I2C device, 0x30. > - */ > - > - /* 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; > - > - 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; > - } > - > - /* 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_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; > - } > - > - 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); > - } > - } > - > - dev_dbg(dp->dev, "EDID Read success!\n"); > - return 0; > -} > - > -static int analogix_dp_handle_edid(struct analogix_dp_device *dp) > -{ > - u8 buf[12]; > - int i; > - int retval; > - > - /* 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; > - > - /* Read EDID */ > - for (i = 0; i < 3; i++) { > - retval = analogix_dp_read_edid(dp); > - if (!retval) > - break; > - } > - > - return retval; > -} > - > static void > analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp, > bool enable) > { > 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)); Note: "DPCD_LANE_COUNT_SET" haven't aligned with "DP_LANE_COUNT_ENHANCED_FRAME_EN" > 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 +120,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 +139,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 +185,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 +210,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); Note: "DP_TRAINING_PATTERN_1 " haven't aligned with "DP_LINK_SCRAMBLING_DISABLE " > + 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 +377,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); Note: "DP_TRAINING_PATTERN_2" haven't aligned with "DP_LINK_SCRAMBLING_DISABLE " > + if (retval < 0) > return retval; > > dev_info(dp->dev, "Link Training Clock Recovery success\n"); > @@ -559,13 +431,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 +449,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 +458,13 @@ 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 +505,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 +524,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 +537,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 +706,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)); > } > } > > @@ -926,12 +793,14 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) > int analogix_dp_get_modes(struct drm_connector *connector) > { > struct analogix_dp_device *dp = to_dp(connector); > - struct edid *edid = (struct edid *)dp->edid; > + struct edid *edid; > int num_modes = 0; > > - if (analogix_dp_handle_edid(dp) == 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); > } > > if (dp->plat_data->panel) > @@ -1231,6 +1100,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) > { > @@ -1355,6 +1232,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..3da338cd3178 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,6 @@ struct analogix_dp_device { > int dpms_mode; > int hpd_gpio; > bool force_hpd; > - unsigned char edid[EDID_BLOCK_LENGTH * 2]; > > struct analogix_dp_plat_data *plat_data; > }; > @@ -206,33 +197,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 +242,6 @@ 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); > +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..7ac4caa6bc1c 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; > @@ -1322,3 +998,130 @@ void analogix_dp_disable_scrambling(struct analogix_dp_device *dp) > reg |= SCRAMBLING_DISABLE; > writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); > } > + > +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; > +}
On 8 August 2016 at 12:43, Yakir Yang <ykk@rock-chips.com> wrote: > + Archit > > Tomeu, > > Thanks for the update :-) > > But you have missed three tiny align problems, please see my inline notes, > wish you could fix them. After that this patch looks good to me, so: > > Reviewed-by: Yakir Yang <ykk@rock-chips.com> Hi Yakir, thanks for remembering the formatting issues and sorry for having missed them before. I don't care much myself, but as the second line isn't an argument to the function, I found it could be misleading if it was aligned as if it was. A quick grep in the DRM sources showed there isn't uniformity on this, so I'm happy to change it to whatever the maintainer prefers. > I guess this patch should go through Archit's drm_bridge tree, so I added > him into the CC list. Cool, thanks again. Archit, do you want me to submit a patch to MAINTAINERS so the tools pick up your address for the right patches? Thanks, Tomeu > > - Yakir > > > > On 08/05/2016 08:59 PM, Tomeu Vizoso wrote: >> >> Remove code for reading the EDID and DPCD fields and use the helpers >> instead. >> >> Besides the obvious code reduction, other helpers are being added to the >> core that could be used in this driver and will be good to be able to >> use them instead of duplicating them. >> >> Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com> >> Tested-by: Javier Martinez Canillas <javier@osg.samsung.com> >> Tested-by: Sean Paul <seanpaul@chromium.org> >> Cc: Javier Martinez Canillas <javier@osg.samsung.com> >> Cc: Mika Kahola <mika.kahola@intel.com> >> Cc: Yakir Yang <ykk@rock-chips.com> >> Cc: Daniel Vetter <daniel.vetter@intel.com> >> >> v2: >> - A bunch of good fixes from Sean and Yakir >> - Moved the transfer function to analogix_dp_reg.c >> - Removed reference to the EDID from the dp struct >> --- >> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 263 ++++-------- >> drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 40 +- >> drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 451 >> ++++++--------------- >> 3 files changed, 204 insertions(+), 550 deletions(-) >> >> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c >> index 32715daf73cb..624fc4f44450 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,150 +98,21 @@ 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 i; >> - unsigned char sum = 0; >> - >> - for (i = 0; i < EDID_BLOCK_LENGTH; i++) >> - sum = sum + edid_data[i]; >> - >> - return sum; >> -} >> - >> -static int analogix_dp_read_edid(struct analogix_dp_device *dp) >> -{ >> - unsigned char *edid = dp->edid; >> - unsigned int extend_block = 0; >> - unsigned char sum; >> - unsigned char test_vector; >> - int retval; >> - >> - /* >> - * EDID device address is 0x50. >> - * However, if necessary, you must have set upper address >> - * into E-EDID in I2C device, 0x30. >> - */ >> - >> - /* 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; >> - >> - 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; >> - } >> - >> - /* 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_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; >> - } >> - >> - 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); >> - } >> - } >> - >> - dev_dbg(dp->dev, "EDID Read success!\n"); >> - return 0; >> -} >> - >> -static int analogix_dp_handle_edid(struct analogix_dp_device *dp) >> -{ >> - u8 buf[12]; >> - int i; >> - int retval; >> - >> - /* 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; >> - >> - /* Read EDID */ >> - for (i = 0; i < 3; i++) { >> - retval = analogix_dp_read_edid(dp); >> - if (!retval) >> - break; >> - } >> - >> - return retval; >> -} >> - >> static void >> analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp, >> bool enable) >> { >> 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)); > > Note: "DPCD_LANE_COUNT_SET" haven't aligned with > "DP_LANE_COUNT_ENHANCED_FRAME_EN" > >> 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 +120,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 +139,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 +185,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 +210,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); > > Note: "DP_TRAINING_PATTERN_1 " haven't aligned with > "DP_LINK_SCRAMBLING_DISABLE " > >> + 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 +377,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); > > Note: "DP_TRAINING_PATTERN_2" haven't aligned with > "DP_LINK_SCRAMBLING_DISABLE " > >> + if (retval < 0) >> return retval; >> dev_info(dp->dev, "Link Training Clock Recovery >> success\n"); >> @@ -559,13 +431,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 +449,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 +458,13 @@ 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 +505,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 +524,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 +537,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 +706,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)); >> } >> } >> @@ -926,12 +793,14 @@ static void analogix_dp_commit(struct >> analogix_dp_device *dp) >> int analogix_dp_get_modes(struct drm_connector *connector) >> { >> struct analogix_dp_device *dp = to_dp(connector); >> - struct edid *edid = (struct edid *)dp->edid; >> + struct edid *edid; >> int num_modes = 0; >> - if (analogix_dp_handle_edid(dp) == 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); >> } >> if (dp->plat_data->panel) >> @@ -1231,6 +1100,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) >> { >> @@ -1355,6 +1232,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..3da338cd3178 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,6 @@ struct analogix_dp_device { >> int dpms_mode; >> int hpd_gpio; >> bool force_hpd; >> - unsigned char edid[EDID_BLOCK_LENGTH * 2]; >> struct analogix_dp_plat_data *plat_data; >> }; >> @@ -206,33 +197,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 +242,6 @@ 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); >> +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..7ac4caa6bc1c 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; >> @@ -1322,3 +998,130 @@ void analogix_dp_disable_scrambling(struct >> analogix_dp_device *dp) >> reg |= SCRAMBLING_DISABLE; >> writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); >> } >> + >> +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; >> +} > > > > _______________________________________________ > dri-devel mailing list > dri-devel@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/dri-devel
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 32715daf73cb..624fc4f44450 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,150 +98,21 @@ 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 i; - unsigned char sum = 0; - - for (i = 0; i < EDID_BLOCK_LENGTH; i++) - sum = sum + edid_data[i]; - - return sum; -} - -static int analogix_dp_read_edid(struct analogix_dp_device *dp) -{ - unsigned char *edid = dp->edid; - unsigned int extend_block = 0; - unsigned char sum; - unsigned char test_vector; - int retval; - - /* - * EDID device address is 0x50. - * However, if necessary, you must have set upper address - * into E-EDID in I2C device, 0x30. - */ - - /* 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; - - 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; - } - - /* 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_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; - } - - 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); - } - } - - dev_dbg(dp->dev, "EDID Read success!\n"); - return 0; -} - -static int analogix_dp_handle_edid(struct analogix_dp_device *dp) -{ - u8 buf[12]; - int i; - int retval; - - /* 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; - - /* Read EDID */ - for (i = 0; i < 3; i++) { - retval = analogix_dp_read_edid(dp); - if (!retval) - break; - } - - return retval; -} - static void analogix_dp_enable_rx_to_enhanced_mode(struct analogix_dp_device *dp, bool enable) { 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 +120,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 +139,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 +185,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 +210,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 +377,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 +431,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 +449,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 +458,13 @@ 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 +505,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 +524,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 +537,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 +706,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)); } } @@ -926,12 +793,14 @@ static void analogix_dp_commit(struct analogix_dp_device *dp) int analogix_dp_get_modes(struct drm_connector *connector) { struct analogix_dp_device *dp = to_dp(connector); - struct edid *edid = (struct edid *)dp->edid; + struct edid *edid; int num_modes = 0; - if (analogix_dp_handle_edid(dp) == 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); } if (dp->plat_data->panel) @@ -1231,6 +1100,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) { @@ -1355,6 +1232,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..3da338cd3178 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,6 @@ struct analogix_dp_device { int dpms_mode; int hpd_gpio; bool force_hpd; - unsigned char edid[EDID_BLOCK_LENGTH * 2]; struct analogix_dp_plat_data *plat_data; }; @@ -206,33 +197,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 +242,6 @@ 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); +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..7ac4caa6bc1c 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; @@ -1322,3 +998,130 @@ void analogix_dp_disable_scrambling(struct analogix_dp_device *dp) reg |= SCRAMBLING_DISABLE; writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); } + +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; +}