aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
diff options
context:
space:
mode:
authorAndrey Grodzovsky <Andrey.Grodzovsky@amd.com>2017-03-28 16:57:52 -0400
committerAlex Deucher <alexander.deucher@amd.com>2017-09-26 17:22:17 -0400
commit7c7f5b15be6528b33d825ead6acb739d7d061a2e (patch)
tree93336895662530093c76410b81c728eec0377f8c /drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
parentdrm/amd/display: Fix i2c write flag. (diff)
downloadlinux-dev-7c7f5b15be6528b33d825ead6acb739d7d061a2e.tar.xz
linux-dev-7c7f5b15be6528b33d825ead6acb739d7d061a2e.zip
drm/amd/display: Refactor edid read.
Allow Linux to use DRM provided EDID read functioality by moving DAL edid implementation to module hence removing this code from DC by this cleaning up DC code for upstream. v2: Removing ddc_service. No more need for it. Signed-off-by: Andrey Grodzovsky <Andrey.Grodzovsky@amd.com> Acked-by: Harry Wentland <Harry.Wentland@amd.com> Reviewed-by: Tony Cheng <Tony.Cheng@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c')
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c337
1 files changed, 9 insertions, 328 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
index 4e9465b630d1..2f5a89c5b063 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
@@ -58,30 +58,6 @@ struct dp_hdmi_dongle_signature_data {
uint8_t eot;/* end of transmition '\x4' */
};
-/* Address range from 0x00 to 0x1F.*/
-#define DP_ADAPTOR_TYPE2_SIZE 0x20
-#define DP_ADAPTOR_TYPE2_REG_ID 0x10
-#define DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK 0x1D
-/* Identifies adaptor as Dual-mode adaptor */
-#define DP_ADAPTOR_TYPE2_ID 0xA0
-/* MHz*/
-#define DP_ADAPTOR_TYPE2_MAX_TMDS_CLK 600
-/* MHz*/
-#define DP_ADAPTOR_TYPE2_MIN_TMDS_CLK 25
-/* kHZ*/
-#define DP_ADAPTOR_DVI_MAX_TMDS_CLK 165000
-/* kHZ*/
-#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 165000
-
-#define DDC_I2C_COMMAND_ENGINE I2C_COMMAND_ENGINE_SW
-
-enum edid_read_result {
- EDID_READ_RESULT_EDID_MATCH = 0,
- EDID_READ_RESULT_EDID_MISMATCH,
- EDID_READ_RESULT_CHECKSUM_READ_ERR,
- EDID_READ_RESULT_VENDOR_READ_ERR
-};
-
/* SCDC Address defines (HDMI 2.0)*/
#define HDMI_SCDC_WRITE_UPDATE_0_ARRAY 3
#define HDMI_SCDC_ADDRESS 0x54
@@ -392,7 +368,7 @@ static uint32_t defer_delay_converter_wa(
#define DP_TRANSLATOR_DELAY 5
-static uint32_t get_defer_delay(struct ddc_service *ddc)
+uint32_t get_defer_delay(struct ddc_service *ddc)
{
uint32_t defer_delay = 0;
@@ -451,307 +427,6 @@ static bool i2c_read(
&command);
}
-static uint8_t aux_read_edid_block(
- struct ddc_service *ddc,
- uint8_t address,
- uint8_t index,
- uint8_t *buf)
-{
- struct aux_command cmd = {
- .payloads = NULL,
- .number_of_payloads = 0,
- .defer_delay = get_defer_delay(ddc),
- .max_defer_write_retry = 0 };
-
- uint8_t retrieved = 0;
- uint8_t base_offset =
- (index % DDC_EDID_BLOCKS_PER_SEGMENT) * DDC_EDID_BLOCK_SIZE;
- uint8_t segment = index / DDC_EDID_BLOCKS_PER_SEGMENT;
-
- for (retrieved = 0; retrieved < DDC_EDID_BLOCK_SIZE;
- retrieved += DEFAULT_AUX_MAX_DATA_SIZE) {
-
- uint8_t offset = base_offset + retrieved;
-
- struct aux_payload payloads[3] = {
- {
- .i2c_over_aux = true,
- .write = true,
- .address = DDC_EDID_SEGMENT_ADDRESS,
- .length = 1,
- .data = &segment },
- {
- .i2c_over_aux = true,
- .write = true,
- .address = address,
- .length = 1,
- .data = &offset },
- {
- .i2c_over_aux = true,
- .write = false,
- .address = address,
- .length = DEFAULT_AUX_MAX_DATA_SIZE,
- .data = &buf[retrieved] } };
-
- if (segment == 0) {
- cmd.payloads = &payloads[1];
- cmd.number_of_payloads = 2;
- } else {
- cmd.payloads = payloads;
- cmd.number_of_payloads = 3;
- }
-
- if (!dal_i2caux_submit_aux_command(
- ddc->ctx->i2caux,
- ddc->ddc_pin,
- &cmd))
- /* cannot read, break*/
- break;
- }
-
- /* Reset segment to 0. Needed by some panels */
- if (0 != segment) {
- struct aux_payload payloads[1] = { {
- .i2c_over_aux = true,
- .write = true,
- .address = DDC_EDID_SEGMENT_ADDRESS,
- .length = 1,
- .data = &segment } };
- bool result = false;
-
- segment = 0;
-
- cmd.number_of_payloads = ARRAY_SIZE(payloads);
- cmd.payloads = payloads;
-
- result = dal_i2caux_submit_aux_command(
- ddc->ctx->i2caux,
- ddc->ddc_pin,
- &cmd);
-
- if (false == result)
- dm_logger_write(
- ddc->ctx->logger, LOG_ERROR,
- "%s: Writing of EDID Segment (0x30) failed!\n",
- __func__);
- }
-
- return retrieved;
-}
-
-static uint8_t i2c_read_edid_block(
- struct ddc_service *ddc,
- uint8_t address,
- uint8_t index,
- uint8_t *buf)
-{
- bool ret = false;
- uint8_t offset = (index % DDC_EDID_BLOCKS_PER_SEGMENT) *
- DDC_EDID_BLOCK_SIZE;
- uint8_t segment = index / DDC_EDID_BLOCKS_PER_SEGMENT;
-
- struct i2c_command cmd = {
- .payloads = NULL,
- .number_of_payloads = 0,
- .engine = DDC_I2C_COMMAND_ENGINE,
- .speed = ddc->ctx->dc->caps.i2c_speed_in_khz };
-
- struct i2c_payload payloads[3] = {
- {
- .write = true,
- .address = DDC_EDID_SEGMENT_ADDRESS,
- .length = 1,
- .data = &segment },
- {
- .write = true,
- .address = address,
- .length = 1,
- .data = &offset },
- {
- .write = false,
- .address = address,
- .length = DDC_EDID_BLOCK_SIZE,
- .data = buf } };
-/*
- * Some I2C engines don't handle stop/start between write-offset and read-data
- * commands properly. For those displays, we have to force the newer E-DDC
- * behavior of repeated-start which can be enabled by runtime parameter. */
-/* Originally implemented for OnLive using NXP receiver chip */
-
- if (index == 0 && !ddc->flags.FORCE_READ_REPEATED_START) {
- /* base block, use use DDC2B, submit as 2 commands */
- cmd.payloads = &payloads[1];
- cmd.number_of_payloads = 1;
-
- if (dm_helpers_submit_i2c(
- ddc->ctx,
- &ddc->link->public,
- &cmd)) {
-
- cmd.payloads = &payloads[2];
- cmd.number_of_payloads = 1;
-
- ret = dm_helpers_submit_i2c(
- ddc->ctx,
- &ddc->link->public,
- &cmd);
- }
-
- } else {
- /*
- * extension block use E-DDC, submit as 1 command
- * or if repeated-start is forced by runtime parameter
- */
- if (segment != 0) {
- /* include segment offset in command*/
- cmd.payloads = payloads;
- cmd.number_of_payloads = 3;
- } else {
- /* we are reading first segment,
- * segment offset is not required */
- cmd.payloads = &payloads[1];
- cmd.number_of_payloads = 2;
- }
-
- ret = dm_helpers_submit_i2c(
- ddc->ctx,
- &ddc->link->public,
- &cmd);
- }
-
- return ret ? DDC_EDID_BLOCK_SIZE : 0;
-}
-
-static uint32_t query_edid_block(
- struct ddc_service *ddc,
- uint8_t address,
- uint8_t index,
- uint8_t *buf,
- uint32_t size)
-{
- uint32_t size_retrieved = 0;
-
- if (size < DDC_EDID_BLOCK_SIZE)
- return 0;
-
- if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) {
- size_retrieved =
- aux_read_edid_block(ddc, address, index, buf);
- } else {
- size_retrieved =
- i2c_read_edid_block(ddc, address, index, buf);
- }
-
- return size_retrieved;
-}
-
-#define DDC_DPCD_EDID_CHECKSUM_WRITE_ADDRESS 0x261
-#define DDC_TEST_ACK_ADDRESS 0x260
-#define DDC_DPCD_EDID_TEST_ACK 0x04
-#define DDC_DPCD_EDID_TEST_MASK 0x04
-#define DDC_DPCD_TEST_REQUEST_ADDRESS 0x218
-
-/* AG TODO GO throug DM callback here like for DPCD */
-
-static void write_dp_edid_checksum(
- struct ddc_service *ddc,
- uint8_t checksum)
-{
- uint8_t dpcd_data;
-
- dal_ddc_service_read_dpcd_data(
- ddc,
- DDC_DPCD_TEST_REQUEST_ADDRESS,
- &dpcd_data,
- 1);
-
- if (dpcd_data & DDC_DPCD_EDID_TEST_MASK) {
-
- dal_ddc_service_write_dpcd_data(
- ddc,
- DDC_DPCD_EDID_CHECKSUM_WRITE_ADDRESS,
- &checksum,
- 1);
-
- dpcd_data = DDC_DPCD_EDID_TEST_ACK;
-
- dal_ddc_service_write_dpcd_data(
- ddc,
- DDC_TEST_ACK_ADDRESS,
- &dpcd_data,
- 1);
- }
-}
-
-uint32_t dal_ddc_service_edid_query(struct ddc_service *ddc)
-{
- uint32_t bytes_read = 0;
- uint32_t ext_cnt = 0;
-
- uint8_t address;
- uint32_t i;
-
- for (address = DDC_EDID_ADDRESS_START;
- address <= DDC_EDID_ADDRESS_END; ++address) {
-
- bytes_read = query_edid_block(
- ddc,
- address,
- 0,
- ddc->edid_buf,
- sizeof(ddc->edid_buf) - bytes_read);
-
- if (bytes_read != DDC_EDID_BLOCK_SIZE)
- continue;
-
- /* get the number of ext blocks*/
- ext_cnt = ddc->edid_buf[DDC_EDID_EXT_COUNT_OFFSET];
-
- /* EDID 2.0, need to read 1 more block because EDID2.0 is
- * 256 byte in size*/
- if (ddc->edid_buf[DDC_EDID_20_SIGNATURE_OFFSET] ==
- DDC_EDID_20_SIGNATURE)
- ext_cnt = 1;
-
- for (i = 0; i < ext_cnt; i++) {
- /* read additional ext blocks accordingly */
- bytes_read += query_edid_block(
- ddc,
- address,
- i+1,
- &ddc->edid_buf[bytes_read],
- sizeof(ddc->edid_buf) - bytes_read);
- }
-
- /*this is special code path for DP compliance*/
- if (DDC_TRANSACTION_TYPE_I2C_OVER_AUX == ddc->transaction_type)
- write_dp_edid_checksum(
- ddc,
- ddc->edid_buf[(ext_cnt * DDC_EDID_BLOCK_SIZE) +
- DDC_EDID1X_CHECKSUM_OFFSET]);
-
- /*remembers the address where we fetch the EDID from
- * for later signature check use */
- ddc->address = address;
-
- break;/* already read edid, done*/
- }
-
- ddc->edid_buf_len = bytes_read;
- return bytes_read;
-}
-
-uint32_t dal_ddc_service_get_edid_buf_len(struct ddc_service *ddc)
-{
- return ddc->edid_buf_len;
-}
-
-void dal_ddc_service_get_edid_buf(struct ddc_service *ddc, uint8_t *edid_buf)
-{
- memmove(edid_buf,
- ddc->edid_buf, ddc->edid_buf_len);
-}
-
void dal_ddc_service_i2c_query_dp_dual_mode_adaptor(
struct ddc_service *ddc,
struct display_sink_capability *sink_cap)
@@ -960,12 +635,14 @@ bool dal_ddc_service_query_ddc_data(
enum ddc_result dal_ddc_service_read_dpcd_data(
struct ddc_service *ddc,
+ bool i2c,
+ enum i2c_mot_mode mot,
uint32_t address,
uint8_t *data,
uint32_t len)
{
struct aux_payload read_payload = {
- .i2c_over_aux = false,
+ .i2c_over_aux = i2c,
.write = false,
.address = address,
.length = len,
@@ -976,6 +653,7 @@ enum ddc_result dal_ddc_service_read_dpcd_data(
.number_of_payloads = 1,
.defer_delay = 0,
.max_defer_write_retry = 0,
+ .mot = mot
};
if (len > DEFAULT_AUX_MAX_DATA_SIZE) {
@@ -994,12 +672,14 @@ enum ddc_result dal_ddc_service_read_dpcd_data(
enum ddc_result dal_ddc_service_write_dpcd_data(
struct ddc_service *ddc,
+ bool i2c,
+ enum i2c_mot_mode mot,
uint32_t address,
const uint8_t *data,
uint32_t len)
{
struct aux_payload write_payload = {
- .i2c_over_aux = false,
+ .i2c_over_aux = i2c,
.write = true,
.address = address,
.length = len,
@@ -1010,6 +690,7 @@ enum ddc_result dal_ddc_service_write_dpcd_data(
.number_of_payloads = 1,
.defer_delay = 0,
.max_defer_write_retry = 0,
+ .mot = mot
};
if (len > DEFAULT_AUX_MAX_DATA_SIZE) {