struct ddc *dal_gpio_service_create_ddc( struct gpio_service *service, uint32_t offset, uint32_t mask, struct gpio_ddc_hw_info *info) { return dal_gpio_create_ddc(service, offset, mask, info); }
void dal_ddc_i2c_payloads_add( struct i2c_payloads *payloads, uint32_t address, uint32_t len, uint8_t *data, bool write) { uint32_t payload_size = EDID_SEGMENT_SIZE; uint32_t pos; for (pos = 0; pos < len; pos += payload_size) { struct i2c_payload payload = { .write = write, .address = address, .length = DDC_MIN(payload_size, len - pos), .data = data + pos }; dal_vector_append(&payloads->payloads, &payload); } } void dal_ddc_aux_payloads_add( struct aux_payloads *payloads, uint32_t address, uint32_t len, uint8_t *data, bool write) { uint32_t payload_size = DEFAULT_AUX_MAX_DATA_SIZE; uint32_t pos; for (pos = 0; pos < len; pos += payload_size) { struct aux_payload payload = { .i2c_over_aux = true, .write = write, .address = address, .length = DDC_MIN(payload_size, len - pos), .data = data + pos }; dal_vector_append(&payloads->payloads, &payload); } } static void construct( struct ddc_service *ddc_service, struct ddc_service_init_data *init_data) { enum connector_id connector_id = dal_graphics_object_id_get_connector_id(init_data->id); struct gpio_service *gpio_service = init_data->ctx->gpio_service; struct graphics_object_i2c_info i2c_info; struct gpio_ddc_hw_info hw_info; struct dc_bios *dcb = init_data->ctx->dc_bios; ddc_service->link = init_data->link; ddc_service->ctx = init_data->ctx; if (BP_RESULT_OK != dcb->funcs->get_i2c_info(dcb, init_data->id, &i2c_info)) { ddc_service->ddc_pin = NULL; } else { hw_info.ddc_channel = i2c_info.i2c_line; hw_info.hw_supported = i2c_info.i2c_hw_assist; ddc_service->ddc_pin = dal_gpio_create_ddc( gpio_service, i2c_info.gpio_info.clk_a_register_index, 1 << i2c_info.gpio_info.clk_a_shift, &hw_info); } ddc_service->flags.EDID_QUERY_DONE_ONCE = false; ddc_service->flags.FORCE_READ_REPEATED_START = false; ddc_service->flags.EDID_STRESS_READ = false; ddc_service->flags.IS_INTERNAL_DISPLAY = connector_id == CONNECTOR_ID_EDP || connector_id == CONNECTOR_ID_LVDS; ddc_service->wa.raw = 0; } struct ddc_service *dal_ddc_service_create( struct ddc_service_init_data *init_data) { struct ddc_service *ddc_service; ddc_service = kzalloc(sizeof(struct ddc_service), GFP_KERNEL); if (!ddc_service) return NULL; construct(ddc_service, init_data); return ddc_service; } static void destruct(struct ddc_service *ddc) { if (ddc->ddc_pin) dal_gpio_destroy_ddc(&ddc->ddc_pin); } void dal_ddc_service_destroy(struct ddc_service **ddc) { if (!ddc || !*ddc) { BREAK_TO_DEBUGGER(); return; } destruct(*ddc); kfree(*ddc); *ddc = NULL; } enum ddc_service_type dal_ddc_service_get_type(struct ddc_service *ddc) { return DDC_SERVICE_TYPE_CONNECTOR; } void dal_ddc_service_set_transaction_type( struct ddc_service *ddc, enum ddc_transaction_type type) { ddc->transaction_type = type; } bool dal_ddc_service_is_in_aux_transaction_mode(struct ddc_service *ddc) { switch (ddc->transaction_type) { case DDC_TRANSACTION_TYPE_I2C_OVER_AUX: case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER: case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_RETRY_DEFER: return true; default: break; } return false; } void ddc_service_set_dongle_type(struct ddc_service *ddc, enum display_dongle_type dongle_type) { ddc->dongle_type = dongle_type; } static uint32_t defer_delay_converter_wa( struct ddc_service *ddc, uint32_t defer_delay) { struct dc_link *link = ddc->link; if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_4 && !memcmp(link->dpcd_caps.branch_dev_name, DP_DVI_CONVERTER_ID_4, sizeof(link->dpcd_caps.branch_dev_name))) return defer_delay > I2C_OVER_AUX_DEFER_WA_DELAY ? defer_delay : I2C_OVER_AUX_DEFER_WA_DELAY; return defer_delay; } #define DP_TRANSLATOR_DELAY 5 uint32_t get_defer_delay(struct ddc_service *ddc) { uint32_t defer_delay = 0; switch (ddc->transaction_type) { case DDC_TRANSACTION_TYPE_I2C_OVER_AUX: if ((DISPLAY_DONGLE_DP_VGA_CONVERTER == ddc->dongle_type) || (DISPLAY_DONGLE_DP_DVI_CONVERTER == ddc->dongle_type) || (DISPLAY_DONGLE_DP_HDMI_CONVERTER == ddc->dongle_type)) { defer_delay = DP_TRANSLATOR_DELAY; defer_delay = defer_delay_converter_wa(ddc, defer_delay); } else /*sink has a delay different from an Active Converter*/ defer_delay = 0; break; case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER: defer_delay = DP_TRANSLATOR_DELAY; break; default: break; } return defer_delay; }