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