diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dc_fused_io.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dc_fused_io.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dc_fused_io.c b/drivers/gpu/drm/amd/display/dc/dc_fused_io.c new file mode 100644 index 000000000000..fee69642fb93 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dc_fused_io.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: MIT +// +// Copyright 2025 Advanced Micro Devices, Inc. + +#include "dc_fused_io.h" + +#include "dm_helpers.h" +#include "gpio.h" + +static bool op_i2c_convert( + union dmub_rb_cmd *cmd, + const struct mod_hdcp_atomic_op_i2c *op, + enum dmub_cmd_fused_request_type type, + uint32_t ddc_line, + bool over_aux +) +{ + struct dmub_cmd_fused_request *req = &cmd->fused_io.request; + struct dmub_cmd_fused_request_location_i2c *loc = &req->u.i2c; + + if (!op || op->size > sizeof(req->buffer)) + return false; + + req->type = type; + loc->is_aux = false; + loc->ddc_line = ddc_line; + loc->over_aux = over_aux; + loc->address = op->address; + loc->offset = op->offset; + loc->length = op->size; + memcpy(req->buffer, op->data, op->size); + + return true; +} + +static bool op_aux_convert( + union dmub_rb_cmd *cmd, + const struct mod_hdcp_atomic_op_aux *op, + enum dmub_cmd_fused_request_type type, + uint32_t ddc_line +) +{ + struct dmub_cmd_fused_request *req = &cmd->fused_io.request; + struct dmub_cmd_fused_request_location_aux *loc = &req->u.aux; + + if (!op || op->size > sizeof(req->buffer)) + return false; + + req->type = type; + loc->is_aux = true; + loc->ddc_line = ddc_line; + loc->address = op->address; + loc->length = op->size; + memcpy(req->buffer, op->data, op->size); + + return true; +} + +static bool atomic_write_poll_read( + struct dc_link *link, + union dmub_rb_cmd commands[3], + uint32_t poll_timeout_us, + uint8_t poll_mask_msb +) +{ + const uint8_t count = 3; + const uint32_t timeout_per_request_us = 10000; + const uint32_t timeout_per_aux_transaction_us = 10000; + uint64_t timeout_us = 0; + + commands[1].fused_io.request.poll_mask_msb = poll_mask_msb; + commands[1].fused_io.request.timeout_us = poll_timeout_us; + + for (uint8_t i = 0; i < count; i++) { + struct dmub_rb_cmd_fused_io *io = &commands[i].fused_io; + + io->header.type = DMUB_CMD__FUSED_IO; + io->header.sub_type = DMUB_CMD__FUSED_IO_EXECUTE; + io->header.multi_cmd_pending = i != count - 1; + io->header.payload_bytes = sizeof(commands[i].fused_io) - sizeof(io->header); + + timeout_us += timeout_per_request_us + io->request.timeout_us; + if (!io->request.timeout_us && io->request.u.aux.is_aux) + timeout_us += timeout_per_aux_transaction_us * (io->request.u.aux.length / 16); + } + + if (!dm_helpers_execute_fused_io(link->ctx, link, commands, count, timeout_us)) + return false; + + return commands[0].fused_io.request.status == FUSED_REQUEST_STATUS_SUCCESS; +} + +bool dm_atomic_write_poll_read_i2c( + struct dc_link *link, + const struct mod_hdcp_atomic_op_i2c *write, + const struct mod_hdcp_atomic_op_i2c *poll, + struct mod_hdcp_atomic_op_i2c *read, + uint32_t poll_timeout_us, + uint8_t poll_mask_msb +) +{ + if (!link) + return false; + + const bool over_aux = false; + const uint32_t ddc_line = link->ddc->ddc_pin->pin_data->en; + + union dmub_rb_cmd commands[3] = { 0 }; + const bool converted = op_i2c_convert(&commands[0], write, FUSED_REQUEST_WRITE, ddc_line, over_aux) + && op_i2c_convert(&commands[1], poll, FUSED_REQUEST_POLL, ddc_line, over_aux) + && op_i2c_convert(&commands[2], read, FUSED_REQUEST_READ, ddc_line, over_aux); + + if (!converted) + return false; + + const bool result = atomic_write_poll_read(link, commands, poll_timeout_us, poll_mask_msb); + + memcpy(read->data, commands[0].fused_io.request.buffer, read->size); + return result; +} + +bool dm_atomic_write_poll_read_aux( + struct dc_link *link, + const struct mod_hdcp_atomic_op_aux *write, + const struct mod_hdcp_atomic_op_aux *poll, + struct mod_hdcp_atomic_op_aux *read, + uint32_t poll_timeout_us, + uint8_t poll_mask_msb +) +{ + if (!link) + return false; + + const uint32_t ddc_line = link->ddc->ddc_pin->pin_data->en; + union dmub_rb_cmd commands[3] = { 0 }; + const bool converted = op_aux_convert(&commands[0], write, FUSED_REQUEST_WRITE, ddc_line) + && op_aux_convert(&commands[1], poll, FUSED_REQUEST_POLL, ddc_line) + && op_aux_convert(&commands[2], read, FUSED_REQUEST_READ, ddc_line); + + if (!converted) + return false; + + const bool result = atomic_write_poll_read(link, commands, poll_timeout_us, poll_mask_msb); + + memcpy(read->data, commands[0].fused_io.request.buffer, read->size); + return result; +} + |