mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-25 18:30:06 +00:00
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>
This commit is contained in:
parent
bb01672c79
commit
7c7f5b15be
15 changed files with 258 additions and 469 deletions
|
@ -435,3 +435,50 @@ bool dm_helpers_submit_i2c(
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
enum dc_edid_status dm_helpers_read_local_edid(
|
||||
struct dc_context *ctx,
|
||||
struct dc_link *link,
|
||||
struct dc_sink *sink)
|
||||
{
|
||||
struct amdgpu_connector *aconnector = link->priv;
|
||||
struct i2c_adapter *ddc;
|
||||
int retry = 3;
|
||||
enum dc_edid_status edid_status;
|
||||
struct edid *edid;
|
||||
|
||||
if (link->aux_mode)
|
||||
ddc = &aconnector->dm_dp_aux.aux.ddc;
|
||||
else
|
||||
ddc = &aconnector->i2c->base;
|
||||
|
||||
/* some dongles read edid incorrectly the first time,
|
||||
* do check sum and retry to make sure read correct edid.
|
||||
*/
|
||||
do {
|
||||
|
||||
edid = drm_get_edid(&aconnector->base, ddc);
|
||||
|
||||
if (!edid)
|
||||
return EDID_NO_RESPONSE;
|
||||
|
||||
sink->dc_edid.length = EDID_LENGTH * (edid->extensions + 1);
|
||||
memmove(sink->dc_edid.raw_edid, (uint8_t *)edid, sink->dc_edid.length);
|
||||
|
||||
/* We don't need the original edid anymore */
|
||||
kfree(edid);
|
||||
|
||||
edid_status = dm_helpers_parse_edid_caps(
|
||||
ctx,
|
||||
&sink->dc_edid,
|
||||
&sink->edid_caps);
|
||||
|
||||
} while (edid_status == EDID_BAD_CHECKSUM && --retry > 0);
|
||||
|
||||
if (edid_status != EDID_OK)
|
||||
DRM_ERROR("EDID err: %d, on connector: %s",
|
||||
edid_status,
|
||||
aconnector->base.name);
|
||||
|
||||
return edid_status;
|
||||
}
|
||||
|
|
|
@ -81,24 +81,43 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg
|
|||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
struct amdgpu_device *adev = drm_dev->dev_private;
|
||||
struct dc *dc = adev->dm.dc;
|
||||
enum i2c_mot_mode mot = (msg->request & DP_AUX_I2C_MOT) ? I2C_MOT_TRUE : I2C_MOT_FALSE;
|
||||
bool res;
|
||||
|
||||
switch (msg->request) {
|
||||
switch (msg->request & ~DP_AUX_I2C_MOT) {
|
||||
case DP_AUX_NATIVE_READ:
|
||||
res = dc_read_dpcd(
|
||||
dc,
|
||||
TO_DM_AUX(aux)->link_index,
|
||||
msg->address,
|
||||
msg->buffer,
|
||||
msg->size);
|
||||
res = dc_read_aux_dpcd(
|
||||
dc,
|
||||
TO_DM_AUX(aux)->link_index,
|
||||
msg->address,
|
||||
msg->buffer,
|
||||
msg->size);
|
||||
break;
|
||||
case DP_AUX_NATIVE_WRITE:
|
||||
res = dc_write_dpcd(
|
||||
dc,
|
||||
TO_DM_AUX(aux)->link_index,
|
||||
msg->address,
|
||||
msg->buffer,
|
||||
msg->size);
|
||||
res = dc_write_aux_dpcd(
|
||||
dc,
|
||||
TO_DM_AUX(aux)->link_index,
|
||||
msg->address,
|
||||
msg->buffer,
|
||||
msg->size);
|
||||
break;
|
||||
case DP_AUX_I2C_READ:
|
||||
res = dc_read_aux_i2c(
|
||||
dc,
|
||||
TO_DM_AUX(aux)->link_index,
|
||||
mot,
|
||||
msg->address,
|
||||
msg->buffer,
|
||||
msg->size);
|
||||
break;
|
||||
case DP_AUX_I2C_WRITE:
|
||||
res = dc_write_aux_i2c(
|
||||
dc,
|
||||
TO_DM_AUX(aux)->link_index,
|
||||
mot,
|
||||
msg->address,
|
||||
msg->buffer,
|
||||
msg->size);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
@ -418,7 +437,7 @@ static const struct drm_dp_mst_topology_cbs dm_mst_cbs = {
|
|||
.register_connector = dm_dp_mst_register_connector
|
||||
};
|
||||
|
||||
void amdgpu_dm_initialize_mst_connector(
|
||||
void amdgpu_dm_initialize_dp_connector(
|
||||
struct amdgpu_display_manager *dm,
|
||||
struct amdgpu_connector *aconnector)
|
||||
{
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
struct amdgpu_display_manager;
|
||||
struct amdgpu_connector;
|
||||
|
||||
void amdgpu_dm_initialize_mst_connector(
|
||||
void amdgpu_dm_initialize_dp_connector(
|
||||
struct amdgpu_display_manager *dm,
|
||||
struct amdgpu_connector *aconnector);
|
||||
|
||||
|
|
|
@ -2047,7 +2047,7 @@ int amdgpu_dm_connector_init(
|
|||
|
||||
if (connector_type == DRM_MODE_CONNECTOR_DisplayPort
|
||||
|| connector_type == DRM_MODE_CONNECTOR_eDP)
|
||||
amdgpu_dm_initialize_mst_connector(dm, aconnector);
|
||||
amdgpu_dm_initialize_dp_connector(dm, aconnector);
|
||||
|
||||
#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
|
||||
defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
|
||||
|
@ -3038,9 +3038,11 @@ static bool is_dp_capable_without_timing_msa(
|
|||
uint8_t dpcd_data;
|
||||
bool capable = false;
|
||||
if (amdgpu_connector->dc_link &&
|
||||
dc_read_dpcd(dc, amdgpu_connector->dc_link->link_index,
|
||||
DP_DOWN_STREAM_PORT_COUNT,
|
||||
&dpcd_data, sizeof(dpcd_data)) )
|
||||
dc_read_aux_dpcd(
|
||||
dc,
|
||||
amdgpu_connector->dc_link->link_index,
|
||||
DP_DOWN_STREAM_PORT_COUNT,
|
||||
&dpcd_data, sizeof(dpcd_data)))
|
||||
capable = (dpcd_data & DP_MSA_TIMING_PAR_IGNORED) ? true:false;
|
||||
|
||||
return capable;
|
||||
|
|
|
@ -1553,7 +1553,7 @@ void dc_resume(const struct dc *dc)
|
|||
core_link_resume(core_dc->links[i]);
|
||||
}
|
||||
|
||||
bool dc_read_dpcd(
|
||||
bool dc_read_aux_dpcd(
|
||||
struct dc *dc,
|
||||
uint32_t link_index,
|
||||
uint32_t address,
|
||||
|
@ -1565,6 +1565,70 @@ bool dc_read_dpcd(
|
|||
struct core_link *link = core_dc->links[link_index];
|
||||
enum ddc_result r = dal_ddc_service_read_dpcd_data(
|
||||
link->ddc,
|
||||
false,
|
||||
I2C_MOT_UNDEF,
|
||||
address,
|
||||
data,
|
||||
size);
|
||||
return r == DDC_RESULT_SUCESSFULL;
|
||||
}
|
||||
|
||||
bool dc_write_aux_dpcd(
|
||||
struct dc *dc,
|
||||
uint32_t link_index,
|
||||
uint32_t address,
|
||||
const uint8_t *data,
|
||||
uint32_t size)
|
||||
{
|
||||
struct core_dc *core_dc = DC_TO_CORE(dc);
|
||||
struct core_link *link = core_dc->links[link_index];
|
||||
|
||||
enum ddc_result r = dal_ddc_service_write_dpcd_data(
|
||||
link->ddc,
|
||||
false,
|
||||
I2C_MOT_UNDEF,
|
||||
address,
|
||||
data,
|
||||
size);
|
||||
return r == DDC_RESULT_SUCESSFULL;
|
||||
}
|
||||
|
||||
bool dc_read_aux_i2c(
|
||||
struct dc *dc,
|
||||
uint32_t link_index,
|
||||
enum i2c_mot_mode mot,
|
||||
uint32_t address,
|
||||
uint8_t *data,
|
||||
uint32_t size)
|
||||
{
|
||||
struct core_dc *core_dc = DC_TO_CORE(dc);
|
||||
|
||||
struct core_link *link = core_dc->links[link_index];
|
||||
enum ddc_result r = dal_ddc_service_read_dpcd_data(
|
||||
link->ddc,
|
||||
true,
|
||||
mot,
|
||||
address,
|
||||
data,
|
||||
size);
|
||||
return r == DDC_RESULT_SUCESSFULL;
|
||||
}
|
||||
|
||||
bool dc_write_aux_i2c(
|
||||
struct dc *dc,
|
||||
uint32_t link_index,
|
||||
enum i2c_mot_mode mot,
|
||||
uint32_t address,
|
||||
const uint8_t *data,
|
||||
uint32_t size)
|
||||
{
|
||||
struct core_dc *core_dc = DC_TO_CORE(dc);
|
||||
struct core_link *link = core_dc->links[link_index];
|
||||
|
||||
enum ddc_result r = dal_ddc_service_write_dpcd_data(
|
||||
link->ddc,
|
||||
true,
|
||||
mot,
|
||||
address,
|
||||
data,
|
||||
size);
|
||||
|
@ -1595,26 +1659,6 @@ bool dc_query_ddc_data(
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool dc_write_dpcd(
|
||||
struct dc *dc,
|
||||
uint32_t link_index,
|
||||
uint32_t address,
|
||||
const uint8_t *data,
|
||||
uint32_t size)
|
||||
{
|
||||
struct core_dc *core_dc = DC_TO_CORE(dc);
|
||||
|
||||
struct core_link *link = core_dc->links[link_index];
|
||||
|
||||
enum ddc_result r = dal_ddc_service_write_dpcd_data(
|
||||
link->ddc,
|
||||
address,
|
||||
data,
|
||||
size);
|
||||
return r == DDC_RESULT_SUCESSFULL;
|
||||
}
|
||||
|
||||
bool dc_submit_i2c(
|
||||
struct dc *dc,
|
||||
uint32_t link_index,
|
||||
|
|
|
@ -464,39 +464,6 @@ static void link_disconnect_sink(struct core_link *link)
|
|||
link->dpcd_sink_count = 0;
|
||||
}
|
||||
|
||||
static enum dc_edid_status read_edid(
|
||||
struct core_link *link,
|
||||
struct core_sink *sink)
|
||||
{
|
||||
uint32_t edid_retry = 3;
|
||||
enum dc_edid_status edid_status;
|
||||
|
||||
/* some dongles read edid incorrectly the first time,
|
||||
* do check sum and retry to make sure read correct edid.
|
||||
*/
|
||||
do {
|
||||
sink->public.dc_edid.length =
|
||||
dal_ddc_service_edid_query(link->ddc);
|
||||
|
||||
if (0 == sink->public.dc_edid.length)
|
||||
return EDID_NO_RESPONSE;
|
||||
|
||||
dal_ddc_service_get_edid_buf(link->ddc,
|
||||
sink->public.dc_edid.raw_edid);
|
||||
edid_status = dm_helpers_parse_edid_caps(
|
||||
sink->ctx,
|
||||
&sink->public.dc_edid,
|
||||
&sink->public.edid_caps);
|
||||
--edid_retry;
|
||||
if (edid_status == EDID_BAD_CHECKSUM)
|
||||
dm_logger_write(link->ctx->logger, LOG_WARNING,
|
||||
"Bad EDID checksum, retry remain: %d\n",
|
||||
edid_retry);
|
||||
} while (edid_status == EDID_BAD_CHECKSUM && edid_retry > 0);
|
||||
|
||||
return edid_status;
|
||||
}
|
||||
|
||||
static void detect_dp(
|
||||
struct core_link *link,
|
||||
struct display_sink_capability *sink_caps,
|
||||
|
@ -673,6 +640,9 @@ bool dc_link_detect(const struct dc_link *dc_link, bool boot)
|
|||
link->ddc,
|
||||
sink_caps.transaction_type);
|
||||
|
||||
link->public.aux_mode = dal_ddc_service_is_in_aux_transaction_mode(
|
||||
link->ddc);
|
||||
|
||||
sink_init_data.link = &link->public;
|
||||
sink_init_data.sink_signal = sink_caps.signal;
|
||||
|
||||
|
@ -688,7 +658,10 @@ bool dc_link_detect(const struct dc_link *dc_link, bool boot)
|
|||
sink = DC_SINK_TO_CORE(dc_sink);
|
||||
link->public.local_sink = &sink->public;
|
||||
|
||||
edid_status = read_edid(link, sink);
|
||||
edid_status = dm_helpers_read_local_edid(
|
||||
link->ctx,
|
||||
&link->public,
|
||||
&sink->public);
|
||||
|
||||
switch (edid_status) {
|
||||
case EDID_BAD_CHECKSUM:
|
||||
|
@ -1500,11 +1473,13 @@ bool dc_link_setup_psr(const struct dc_link *dc_link,
|
|||
*/
|
||||
psr_configuration.bits.IRQ_HPD_WITH_CRC_ERROR = 1;
|
||||
}
|
||||
dal_ddc_service_write_dpcd_data(
|
||||
link->ddc,
|
||||
368,
|
||||
&psr_configuration.raw,
|
||||
sizeof(psr_configuration.raw));
|
||||
|
||||
dm_helpers_dp_write_dpcd(
|
||||
link->ctx,
|
||||
dc_link,
|
||||
368,
|
||||
&psr_configuration.raw,
|
||||
sizeof(psr_configuration.raw));
|
||||
|
||||
psr_context.channel = link->ddc->ddc_pin->hw_info.ddc_channel;
|
||||
if (psr_context.channel == 0)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -1481,22 +1481,25 @@ static bool handle_hpd_irq_psr_sink(const struct core_link *link)
|
|||
if (link->public.psr_caps.psr_version == 0)
|
||||
return false;
|
||||
|
||||
dal_ddc_service_read_dpcd_data(
|
||||
link->ddc,
|
||||
368 /*DpcdAddress_PSR_Enable_Cfg*/,
|
||||
&psr_configuration.raw,
|
||||
sizeof(psr_configuration.raw));
|
||||
dm_helpers_dp_read_dpcd(
|
||||
link->ctx,
|
||||
&link->public,
|
||||
368,/*DpcdAddress_PSR_Enable_Cfg*/
|
||||
&psr_configuration.raw,
|
||||
sizeof(psr_configuration.raw));
|
||||
|
||||
|
||||
if (psr_configuration.bits.ENABLE) {
|
||||
unsigned char dpcdbuf[3] = {0};
|
||||
union psr_error_status psr_error_status;
|
||||
union psr_sink_psr_status psr_sink_psr_status;
|
||||
|
||||
dal_ddc_service_read_dpcd_data(
|
||||
link->ddc,
|
||||
0x2006 /*DpcdAddress_PSR_Error_Status*/,
|
||||
(unsigned char *) dpcdbuf,
|
||||
sizeof(dpcdbuf));
|
||||
dm_helpers_dp_read_dpcd(
|
||||
link->ctx,
|
||||
&link->public,
|
||||
0x2006, /*DpcdAddress_PSR_Error_Status*/
|
||||
(unsigned char *) dpcdbuf,
|
||||
sizeof(dpcdbuf));
|
||||
|
||||
/*DPCD 2006h ERROR STATUS*/
|
||||
psr_error_status.raw = dpcdbuf[0];
|
||||
|
@ -1506,9 +1509,10 @@ static bool handle_hpd_irq_psr_sink(const struct core_link *link)
|
|||
if (psr_error_status.bits.LINK_CRC_ERROR ||
|
||||
psr_error_status.bits.RFB_STORAGE_ERROR) {
|
||||
/* Acknowledge and clear error bits */
|
||||
dal_ddc_service_write_dpcd_data(
|
||||
link->ddc,
|
||||
8198 /*DpcdAddress_PSR_Error_Status*/,
|
||||
dm_helpers_dp_write_dpcd(
|
||||
link->ctx,
|
||||
&link->public,
|
||||
8198,/*DpcdAddress_PSR_Error_Status*/
|
||||
&psr_error_status.raw,
|
||||
sizeof(psr_error_status.raw));
|
||||
|
||||
|
|
|
@ -594,6 +594,7 @@ struct dc_link {
|
|||
union compliance_test_state compliance_test_state;
|
||||
|
||||
void *priv;
|
||||
bool aux_mode;
|
||||
};
|
||||
|
||||
struct dpcd_caps {
|
||||
|
@ -788,20 +789,36 @@ const struct ddc_service *dc_get_ddc_at_index(
|
|||
* DPCD access interfaces
|
||||
*/
|
||||
|
||||
bool dc_read_dpcd(
|
||||
bool dc_read_aux_dpcd(
|
||||
struct dc *dc,
|
||||
uint32_t link_index,
|
||||
uint32_t address,
|
||||
uint8_t *data,
|
||||
uint32_t size);
|
||||
|
||||
bool dc_write_dpcd(
|
||||
bool dc_write_aux_dpcd(
|
||||
struct dc *dc,
|
||||
uint32_t link_index,
|
||||
uint32_t address,
|
||||
const uint8_t *data,
|
||||
uint32_t size);
|
||||
|
||||
bool dc_read_aux_i2c(
|
||||
struct dc *dc,
|
||||
uint32_t link_index,
|
||||
enum i2c_mot_mode mot,
|
||||
uint32_t address,
|
||||
uint8_t *data,
|
||||
uint32_t size);
|
||||
|
||||
bool dc_write_aux_i2c(
|
||||
struct dc *dc,
|
||||
uint32_t link_index,
|
||||
enum i2c_mot_mode mot,
|
||||
uint32_t address,
|
||||
const uint8_t *data,
|
||||
uint32_t size);
|
||||
|
||||
bool dc_query_ddc_data(
|
||||
struct dc *dc,
|
||||
uint32_t link_index,
|
||||
|
|
|
@ -489,4 +489,10 @@ struct psr_caps {
|
|||
unsigned int psr_sdp_transmit_line_num_deadline;
|
||||
};
|
||||
|
||||
enum i2c_mot_mode {
|
||||
I2C_MOT_UNDEF,
|
||||
I2C_MOT_TRUE,
|
||||
I2C_MOT_FALSE
|
||||
};
|
||||
|
||||
#endif /* DC_TYPES_H_ */
|
||||
|
|
|
@ -98,4 +98,14 @@ bool dm_helpers_submit_i2c(
|
|||
struct i2c_command *cmd);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
enum dc_edid_status dm_helpers_read_local_edid(
|
||||
struct dc_context *ctx,
|
||||
struct dc_link *link,
|
||||
struct dc_sink *sink);
|
||||
|
||||
|
||||
#endif /* __DM_HELPERS__ */
|
||||
|
|
|
@ -185,6 +185,7 @@ bool dal_i2caux_submit_aux_command(
|
|||
struct aux_engine *engine;
|
||||
uint8_t index_of_payload = 0;
|
||||
bool result;
|
||||
bool mot;
|
||||
|
||||
if (!ddc) {
|
||||
BREAK_TO_DEBUGGER();
|
||||
|
@ -207,12 +208,14 @@ bool dal_i2caux_submit_aux_command(
|
|||
result = true;
|
||||
|
||||
while (index_of_payload < cmd->number_of_payloads) {
|
||||
bool mot = (index_of_payload != cmd->number_of_payloads - 1);
|
||||
|
||||
struct aux_payload *payload = cmd->payloads + index_of_payload;
|
||||
|
||||
struct i2caux_transaction_request request = { 0 };
|
||||
|
||||
if (cmd->mot == I2C_MOT_UNDEF)
|
||||
mot = (index_of_payload != cmd->number_of_payloads - 1);
|
||||
else
|
||||
mot = (cmd->mot == I2C_MOT_TRUE);
|
||||
|
||||
request.operation = payload->write ?
|
||||
I2CAUX_TRANSACTION_WRITE :
|
||||
I2CAUX_TRANSACTION_READ;
|
||||
|
|
|
@ -31,6 +31,23 @@
|
|||
|
||||
#define EDID_SEGMENT_SIZE 256
|
||||
|
||||
/* 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
|
||||
|
||||
struct ddc_service;
|
||||
struct graphics_object_id;
|
||||
enum ddc_result;
|
||||
|
@ -83,12 +100,6 @@ void dal_ddc_service_set_transaction_type(
|
|||
|
||||
bool dal_ddc_service_is_in_aux_transaction_mode(struct ddc_service *ddc);
|
||||
|
||||
uint32_t dal_ddc_service_edid_query(struct ddc_service *ddc);
|
||||
|
||||
uint32_t dal_ddc_service_get_edid_buf_len(struct ddc_service *ddc);
|
||||
|
||||
void dal_ddc_service_get_edid_buf(struct ddc_service *ddc, uint8_t *edid_buf);
|
||||
|
||||
void dal_ddc_service_i2c_query_dp_dual_mode_adaptor(
|
||||
struct ddc_service *ddc,
|
||||
struct display_sink_capability *sink_cap);
|
||||
|
@ -103,12 +114,16 @@ 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);
|
||||
|
||||
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);
|
||||
|
@ -130,16 +145,7 @@ void dal_ddc_service_set_ddc_pin(
|
|||
|
||||
struct ddc *dal_ddc_service_get_ddc_pin(struct ddc_service *ddc_service);
|
||||
|
||||
enum ddc_result dal_ddc_service_read_dpcd_data(
|
||||
struct ddc_service *ddc,
|
||||
uint32_t address,
|
||||
uint8_t *data,
|
||||
uint32_t len);
|
||||
enum ddc_result dal_ddc_service_write_dpcd_data(
|
||||
struct ddc_service *ddc,
|
||||
uint32_t address,
|
||||
const uint8_t *data,
|
||||
uint32_t len);
|
||||
uint32_t get_defer_delay(struct ddc_service *ddc);
|
||||
|
||||
#endif /* __DAL_DDC_SERVICE_H__ */
|
||||
|
||||
|
|
|
@ -115,34 +115,6 @@ struct av_sync_data {
|
|||
uint8_t aud_del_ins3;/* DPCD 0002Dh */
|
||||
};
|
||||
|
||||
/** EDID retrieval related constants, also used by MstMgr **/
|
||||
|
||||
#define DDC_EDID_SEGMENT_SIZE 256
|
||||
#define DDC_EDID_BLOCK_SIZE 128
|
||||
#define DDC_EDID_BLOCKS_PER_SEGMENT \
|
||||
(DDC_EDID_SEGMENT_SIZE / DDC_EDID_BLOCK_SIZE)
|
||||
|
||||
#define DDC_EDID_EXT_COUNT_OFFSET 0x7E
|
||||
|
||||
#define DDC_EDID_ADDRESS_START 0x50
|
||||
#define DDC_EDID_ADDRESS_END 0x52
|
||||
#define DDC_EDID_SEGMENT_ADDRESS 0x30
|
||||
|
||||
/* signatures for Edid 1x */
|
||||
#define DDC_EDID1X_VENDORID_SIGNATURE_OFFSET 8
|
||||
#define DDC_EDID1X_VENDORID_SIGNATURE_LEN 4
|
||||
#define DDC_EDID1X_EXT_CNT_AND_CHECKSUM_OFFSET 126
|
||||
#define DDC_EDID1X_EXT_CNT_AND_CHECKSUM_LEN 2
|
||||
#define DDC_EDID1X_CHECKSUM_OFFSET 127
|
||||
/* signatures for Edid 20*/
|
||||
#define DDC_EDID_20_SIGNATURE_OFFSET 0
|
||||
#define DDC_EDID_20_SIGNATURE 0x20
|
||||
|
||||
#define DDC_EDID20_VENDORID_SIGNATURE_OFFSET 1
|
||||
#define DDC_EDID20_VENDORID_SIGNATURE_LEN 4
|
||||
#define DDC_EDID20_CHECKSUM_OFFSET 255
|
||||
#define DDC_EDID20_CHECKSUM_LEN 1
|
||||
|
||||
/*DP to VGA converter*/
|
||||
static const uint8_t DP_VGA_CONVERTER_ID_1[] = "mVGAa";
|
||||
/*DP to Dual link DVI converter*/
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#ifndef __DAL_I2CAUX_INTERFACE_H__
|
||||
#define __DAL_I2CAUX_INTERFACE_H__
|
||||
|
||||
#include "dc_types.h"
|
||||
#include "gpio_service_interface.h"
|
||||
|
||||
|
||||
|
@ -54,6 +55,8 @@ struct aux_command {
|
|||
|
||||
/* zero means "use default value" */
|
||||
uint32_t max_defer_write_retry;
|
||||
|
||||
enum i2c_mot_mode mot;
|
||||
};
|
||||
|
||||
union aux_config {
|
||||
|
|
Loading…
Reference in a new issue