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
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)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
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)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
atomic_write_poll_read(struct dc_link * link,union dmub_rb_cmd commands[3],uint32_t poll_timeout_us,uint8_t poll_mask_msb)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
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)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
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)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