1 // SPDX-License-Identifier: MIT 2 // 3 // Copyright 2025 Advanced Micro Devices, Inc. 4 5 #include "dc_fused_io.h" 6 7 #include "dm_helpers.h" 8 #include "gpio.h" 9 10 static bool op_i2c_convert( 11 union dmub_rb_cmd *cmd, 12 const struct mod_hdcp_atomic_op_i2c *op, 13 enum dmub_cmd_fused_request_type type, 14 uint32_t ddc_line, 15 bool over_aux 16 ) 17 { 18 struct dmub_cmd_fused_request *req = &cmd->fused_io.request; 19 struct dmub_cmd_fused_request_location_i2c *loc = &req->u.i2c; 20 21 if (!op || op->size > sizeof(req->buffer)) 22 return false; 23 24 req->type = type; 25 loc->is_aux = false; 26 loc->ddc_line = ddc_line; 27 loc->over_aux = over_aux; 28 loc->address = op->address; 29 loc->offset = op->offset; 30 loc->length = op->size; 31 memcpy(req->buffer, op->data, op->size); 32 33 return true; 34 } 35 36 static bool op_aux_convert( 37 union dmub_rb_cmd *cmd, 38 const struct mod_hdcp_atomic_op_aux *op, 39 enum dmub_cmd_fused_request_type type, 40 uint32_t ddc_line 41 ) 42 { 43 struct dmub_cmd_fused_request *req = &cmd->fused_io.request; 44 struct dmub_cmd_fused_request_location_aux *loc = &req->u.aux; 45 46 if (!op || op->size > sizeof(req->buffer)) 47 return false; 48 49 req->type = type; 50 loc->is_aux = true; 51 loc->ddc_line = ddc_line; 52 loc->address = op->address; 53 loc->length = op->size; 54 memcpy(req->buffer, op->data, op->size); 55 56 return true; 57 } 58 59 static bool atomic_write_poll_read( 60 struct dc_link *link, 61 union dmub_rb_cmd commands[3], 62 uint32_t poll_timeout_us, 63 uint8_t poll_mask_msb 64 ) 65 { 66 const uint8_t count = 3; 67 const uint32_t timeout_per_request_us = 10000; 68 const uint32_t timeout_per_aux_transaction_us = 10000; 69 uint64_t timeout_us = 0; 70 71 commands[1].fused_io.request.poll_mask_msb = poll_mask_msb; 72 commands[1].fused_io.request.timeout_us = poll_timeout_us; 73 74 for (uint8_t i = 0; i < count; i++) { 75 struct dmub_rb_cmd_fused_io *io = &commands[i].fused_io; 76 77 io->header.type = DMUB_CMD__FUSED_IO; 78 io->header.sub_type = DMUB_CMD__FUSED_IO_EXECUTE; 79 io->header.multi_cmd_pending = i != count - 1; 80 io->header.payload_bytes = sizeof(commands[i].fused_io) - sizeof(io->header); 81 82 timeout_us += timeout_per_request_us + io->request.timeout_us; 83 if (!io->request.timeout_us && io->request.u.aux.is_aux) 84 timeout_us += timeout_per_aux_transaction_us * (io->request.u.aux.length / 16); 85 } 86 87 if (!dm_helpers_execute_fused_io(link->ctx, link, commands, count, timeout_us)) 88 return false; 89 90 return commands[0].fused_io.request.status == FUSED_REQUEST_STATUS_SUCCESS; 91 } 92 93 bool dm_atomic_write_poll_read_i2c( 94 struct dc_link *link, 95 const struct mod_hdcp_atomic_op_i2c *write, 96 const struct mod_hdcp_atomic_op_i2c *poll, 97 struct mod_hdcp_atomic_op_i2c *read, 98 uint32_t poll_timeout_us, 99 uint8_t poll_mask_msb 100 ) 101 { 102 if (!link) 103 return false; 104 105 const bool over_aux = false; 106 const uint32_t ddc_line = link->ddc->ddc_pin->pin_data->en; 107 108 union dmub_rb_cmd commands[3] = { 0 }; 109 const bool converted = op_i2c_convert(&commands[0], write, FUSED_REQUEST_WRITE, ddc_line, over_aux) 110 && op_i2c_convert(&commands[1], poll, FUSED_REQUEST_POLL, ddc_line, over_aux) 111 && op_i2c_convert(&commands[2], read, FUSED_REQUEST_READ, ddc_line, over_aux); 112 113 if (!converted) 114 return false; 115 116 const bool result = atomic_write_poll_read(link, commands, poll_timeout_us, poll_mask_msb); 117 118 memcpy(read->data, commands[0].fused_io.request.buffer, read->size); 119 return result; 120 } 121 122 bool dm_atomic_write_poll_read_aux( 123 struct dc_link *link, 124 const struct mod_hdcp_atomic_op_aux *write, 125 const struct mod_hdcp_atomic_op_aux *poll, 126 struct mod_hdcp_atomic_op_aux *read, 127 uint32_t poll_timeout_us, 128 uint8_t poll_mask_msb 129 ) 130 { 131 if (!link) 132 return false; 133 134 const uint32_t ddc_line = link->ddc->ddc_pin->pin_data->en; 135 union dmub_rb_cmd commands[3] = { 0 }; 136 const bool converted = op_aux_convert(&commands[0], write, FUSED_REQUEST_WRITE, ddc_line) 137 && op_aux_convert(&commands[1], poll, FUSED_REQUEST_POLL, ddc_line) 138 && op_aux_convert(&commands[2], read, FUSED_REQUEST_READ, ddc_line); 139 140 if (!converted) 141 return false; 142 143 const bool result = atomic_write_poll_read(link, commands, poll_timeout_us, poll_mask_msb); 144 145 memcpy(read->data, commands[0].fused_io.request.buffer, read->size); 146 return result; 147 } 148 149