1b843c749SSergey Zigachev /*
2b843c749SSergey Zigachev * Copyright 2012-15 Advanced Micro Devices, Inc.
3b843c749SSergey Zigachev *
4b843c749SSergey Zigachev * Permission is hereby granted, free of charge, to any person obtaining a
5b843c749SSergey Zigachev * copy of this software and associated documentation files (the "Software"),
6b843c749SSergey Zigachev * to deal in the Software without restriction, including without limitation
7b843c749SSergey Zigachev * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b843c749SSergey Zigachev * and/or sell copies of the Software, and to permit persons to whom the
9b843c749SSergey Zigachev * Software is furnished to do so, subject to the following conditions:
10b843c749SSergey Zigachev *
11b843c749SSergey Zigachev * The above copyright notice and this permission notice shall be included in
12b843c749SSergey Zigachev * all copies or substantial portions of the Software.
13b843c749SSergey Zigachev *
14b843c749SSergey Zigachev * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15b843c749SSergey Zigachev * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16b843c749SSergey Zigachev * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17b843c749SSergey Zigachev * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18b843c749SSergey Zigachev * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19b843c749SSergey Zigachev * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20b843c749SSergey Zigachev * OTHER DEALINGS IN THE SOFTWARE.
21b843c749SSergey Zigachev *
22b843c749SSergey Zigachev * Authors: AMD
23b843c749SSergey Zigachev *
24b843c749SSergey Zigachev */
25b843c749SSergey Zigachev
26b843c749SSergey Zigachev #include "dm_services.h"
27b843c749SSergey Zigachev #include "dce_aux.h"
28b843c749SSergey Zigachev #include "dce/dce_11_0_sh_mask.h"
29b843c749SSergey Zigachev
30b843c749SSergey Zigachev #define CTX \
31b843c749SSergey Zigachev aux110->base.ctx
32b843c749SSergey Zigachev #define REG(reg_name)\
33b843c749SSergey Zigachev (aux110->regs->reg_name)
34b843c749SSergey Zigachev
35b843c749SSergey Zigachev #define DC_LOGGER \
36b843c749SSergey Zigachev engine->ctx->logger
37b843c749SSergey Zigachev
38b843c749SSergey Zigachev #include "reg_helper.h"
39b843c749SSergey Zigachev
40b843c749SSergey Zigachev #define FROM_AUX_ENGINE(ptr) \
41b843c749SSergey Zigachev container_of((ptr), struct aux_engine_dce110, base)
42b843c749SSergey Zigachev
43b843c749SSergey Zigachev #define FROM_ENGINE(ptr) \
44b843c749SSergey Zigachev FROM_AUX_ENGINE(container_of((ptr), struct aux_engine, base))
45b843c749SSergey Zigachev
46b843c749SSergey Zigachev #define FROM_AUX_ENGINE_ENGINE(ptr) \
47b843c749SSergey Zigachev container_of((ptr), struct aux_engine, base)
48b843c749SSergey Zigachev enum {
49b843c749SSergey Zigachev AUX_INVALID_REPLY_RETRY_COUNTER = 1,
50b843c749SSergey Zigachev AUX_TIMED_OUT_RETRY_COUNTER = 2,
51b843c749SSergey Zigachev AUX_DEFER_RETRY_COUNTER = 6
52b843c749SSergey Zigachev };
release_engine(struct aux_engine * engine)53b843c749SSergey Zigachev static void release_engine(
54b843c749SSergey Zigachev struct aux_engine *engine)
55b843c749SSergey Zigachev {
56b843c749SSergey Zigachev struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
57b843c749SSergey Zigachev
58b843c749SSergey Zigachev dal_ddc_close(engine->ddc);
59b843c749SSergey Zigachev
60b843c749SSergey Zigachev engine->ddc = NULL;
61b843c749SSergey Zigachev
62b843c749SSergey Zigachev REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1);
63b843c749SSergey Zigachev }
64b843c749SSergey Zigachev
65b843c749SSergey Zigachev #define SW_CAN_ACCESS_AUX 1
66b843c749SSergey Zigachev #define DMCU_CAN_ACCESS_AUX 2
67b843c749SSergey Zigachev
is_engine_available(struct aux_engine * engine)68b843c749SSergey Zigachev static bool is_engine_available(
69b843c749SSergey Zigachev struct aux_engine *engine)
70b843c749SSergey Zigachev {
71b843c749SSergey Zigachev struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
72b843c749SSergey Zigachev
73b843c749SSergey Zigachev uint32_t value = REG_READ(AUX_ARB_CONTROL);
74b843c749SSergey Zigachev uint32_t field = get_reg_field_value(
75b843c749SSergey Zigachev value,
76b843c749SSergey Zigachev AUX_ARB_CONTROL,
77b843c749SSergey Zigachev AUX_REG_RW_CNTL_STATUS);
78b843c749SSergey Zigachev
79b843c749SSergey Zigachev return (field != DMCU_CAN_ACCESS_AUX);
80b843c749SSergey Zigachev }
acquire_engine(struct aux_engine * engine)81b843c749SSergey Zigachev static bool acquire_engine(
82b843c749SSergey Zigachev struct aux_engine *engine)
83b843c749SSergey Zigachev {
84b843c749SSergey Zigachev struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
85b843c749SSergey Zigachev
86b843c749SSergey Zigachev uint32_t value = REG_READ(AUX_ARB_CONTROL);
87b843c749SSergey Zigachev uint32_t field = get_reg_field_value(
88b843c749SSergey Zigachev value,
89b843c749SSergey Zigachev AUX_ARB_CONTROL,
90b843c749SSergey Zigachev AUX_REG_RW_CNTL_STATUS);
91b843c749SSergey Zigachev if (field == DMCU_CAN_ACCESS_AUX)
92b843c749SSergey Zigachev return false;
93b843c749SSergey Zigachev /* enable AUX before request SW to access AUX */
94b843c749SSergey Zigachev value = REG_READ(AUX_CONTROL);
95b843c749SSergey Zigachev field = get_reg_field_value(value,
96b843c749SSergey Zigachev AUX_CONTROL,
97b843c749SSergey Zigachev AUX_EN);
98b843c749SSergey Zigachev
99b843c749SSergey Zigachev if (field == 0) {
100b843c749SSergey Zigachev set_reg_field_value(
101b843c749SSergey Zigachev value,
102b843c749SSergey Zigachev 1,
103b843c749SSergey Zigachev AUX_CONTROL,
104b843c749SSergey Zigachev AUX_EN);
105b843c749SSergey Zigachev
106b843c749SSergey Zigachev if (REG(AUX_RESET_MASK)) {
107b843c749SSergey Zigachev /*DP_AUX block as part of the enable sequence*/
108b843c749SSergey Zigachev set_reg_field_value(
109b843c749SSergey Zigachev value,
110b843c749SSergey Zigachev 1,
111b843c749SSergey Zigachev AUX_CONTROL,
112b843c749SSergey Zigachev AUX_RESET);
113b843c749SSergey Zigachev }
114b843c749SSergey Zigachev
115b843c749SSergey Zigachev REG_WRITE(AUX_CONTROL, value);
116b843c749SSergey Zigachev
117b843c749SSergey Zigachev if (REG(AUX_RESET_MASK)) {
118b843c749SSergey Zigachev /*poll HW to make sure reset it done*/
119b843c749SSergey Zigachev
120b843c749SSergey Zigachev REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 1,
121b843c749SSergey Zigachev 1, 11);
122b843c749SSergey Zigachev
123b843c749SSergey Zigachev set_reg_field_value(
124b843c749SSergey Zigachev value,
125b843c749SSergey Zigachev 0,
126b843c749SSergey Zigachev AUX_CONTROL,
127b843c749SSergey Zigachev AUX_RESET);
128b843c749SSergey Zigachev
129b843c749SSergey Zigachev REG_WRITE(AUX_CONTROL, value);
130b843c749SSergey Zigachev
131b843c749SSergey Zigachev REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 0,
132b843c749SSergey Zigachev 1, 11);
133b843c749SSergey Zigachev }
134b843c749SSergey Zigachev } /*if (field)*/
135b843c749SSergey Zigachev
136b843c749SSergey Zigachev /* request SW to access AUX */
137b843c749SSergey Zigachev REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_USE_AUX_REG_REQ, 1);
138b843c749SSergey Zigachev
139b843c749SSergey Zigachev value = REG_READ(AUX_ARB_CONTROL);
140b843c749SSergey Zigachev field = get_reg_field_value(
141b843c749SSergey Zigachev value,
142b843c749SSergey Zigachev AUX_ARB_CONTROL,
143b843c749SSergey Zigachev AUX_REG_RW_CNTL_STATUS);
144b843c749SSergey Zigachev
145b843c749SSergey Zigachev return (field == SW_CAN_ACCESS_AUX);
146b843c749SSergey Zigachev }
147b843c749SSergey Zigachev
148b843c749SSergey Zigachev #define COMPOSE_AUX_SW_DATA_16_20(command, address) \
149b843c749SSergey Zigachev ((command) | ((0xF0000 & (address)) >> 16))
150b843c749SSergey Zigachev
151b843c749SSergey Zigachev #define COMPOSE_AUX_SW_DATA_8_15(address) \
152b843c749SSergey Zigachev ((0xFF00 & (address)) >> 8)
153b843c749SSergey Zigachev
154b843c749SSergey Zigachev #define COMPOSE_AUX_SW_DATA_0_7(address) \
155b843c749SSergey Zigachev (0xFF & (address))
156b843c749SSergey Zigachev
submit_channel_request(struct aux_engine * engine,struct aux_request_transaction_data * request)157b843c749SSergey Zigachev static void submit_channel_request(
158b843c749SSergey Zigachev struct aux_engine *engine,
159b843c749SSergey Zigachev struct aux_request_transaction_data *request)
160b843c749SSergey Zigachev {
161b843c749SSergey Zigachev struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
162b843c749SSergey Zigachev uint32_t value;
163b843c749SSergey Zigachev uint32_t length;
164b843c749SSergey Zigachev
165b843c749SSergey Zigachev bool is_write =
166b843c749SSergey Zigachev ((request->type == AUX_TRANSACTION_TYPE_DP) &&
167b843c749SSergey Zigachev (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) ||
168b843c749SSergey Zigachev ((request->type == AUX_TRANSACTION_TYPE_I2C) &&
169b843c749SSergey Zigachev ((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
170b843c749SSergey Zigachev (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT)));
171b843c749SSergey Zigachev if (REG(AUXN_IMPCAL)) {
172b843c749SSergey Zigachev /* clear_aux_error */
173b843c749SSergey Zigachev REG_UPDATE_SEQ(AUXN_IMPCAL, AUXN_CALOUT_ERROR_AK,
174b843c749SSergey Zigachev 1,
175b843c749SSergey Zigachev 0);
176b843c749SSergey Zigachev
177b843c749SSergey Zigachev REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_CALOUT_ERROR_AK,
178b843c749SSergey Zigachev 1,
179b843c749SSergey Zigachev 0);
180b843c749SSergey Zigachev
181b843c749SSergey Zigachev /* force_default_calibrate */
182b843c749SSergey Zigachev REG_UPDATE_1BY1_2(AUXN_IMPCAL,
183b843c749SSergey Zigachev AUXN_IMPCAL_ENABLE, 1,
184b843c749SSergey Zigachev AUXN_IMPCAL_OVERRIDE_ENABLE, 0);
185b843c749SSergey Zigachev
186b843c749SSergey Zigachev /* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */
187b843c749SSergey Zigachev
188b843c749SSergey Zigachev REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_IMPCAL_OVERRIDE_ENABLE,
189b843c749SSergey Zigachev 1,
190b843c749SSergey Zigachev 0);
191b843c749SSergey Zigachev }
192b843c749SSergey Zigachev
193b843c749SSergey Zigachev REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1);
194b843c749SSergey Zigachev
195b843c749SSergey Zigachev REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0,
196b843c749SSergey Zigachev 10, aux110->timeout_period/10);
197b843c749SSergey Zigachev
198b843c749SSergey Zigachev /* set the delay and the number of bytes to write */
199b843c749SSergey Zigachev
200b843c749SSergey Zigachev /* The length include
201b843c749SSergey Zigachev * the 4 bit header and the 20 bit address
202b843c749SSergey Zigachev * (that is 3 byte).
203b843c749SSergey Zigachev * If the requested length is non zero this means
204b843c749SSergey Zigachev * an addition byte specifying the length is required.
205b843c749SSergey Zigachev */
206b843c749SSergey Zigachev
207b843c749SSergey Zigachev length = request->length ? 4 : 3;
208b843c749SSergey Zigachev if (is_write)
209b843c749SSergey Zigachev length += request->length;
210b843c749SSergey Zigachev
211b843c749SSergey Zigachev REG_UPDATE_2(AUX_SW_CONTROL,
212b843c749SSergey Zigachev AUX_SW_START_DELAY, request->delay,
213b843c749SSergey Zigachev AUX_SW_WR_BYTES, length);
214b843c749SSergey Zigachev
215b843c749SSergey Zigachev /* program action and address and payload data (if 'is_write') */
216b843c749SSergey Zigachev value = REG_UPDATE_4(AUX_SW_DATA,
217b843c749SSergey Zigachev AUX_SW_INDEX, 0,
218b843c749SSergey Zigachev AUX_SW_DATA_RW, 0,
219b843c749SSergey Zigachev AUX_SW_AUTOINCREMENT_DISABLE, 1,
220b843c749SSergey Zigachev AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address));
221b843c749SSergey Zigachev
222b843c749SSergey Zigachev value = REG_SET_2(AUX_SW_DATA, value,
223b843c749SSergey Zigachev AUX_SW_AUTOINCREMENT_DISABLE, 0,
224b843c749SSergey Zigachev AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address));
225b843c749SSergey Zigachev
226b843c749SSergey Zigachev value = REG_SET(AUX_SW_DATA, value,
227b843c749SSergey Zigachev AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address));
228b843c749SSergey Zigachev
229b843c749SSergey Zigachev if (request->length) {
230b843c749SSergey Zigachev value = REG_SET(AUX_SW_DATA, value,
231b843c749SSergey Zigachev AUX_SW_DATA, request->length - 1);
232b843c749SSergey Zigachev }
233b843c749SSergey Zigachev
234b843c749SSergey Zigachev if (is_write) {
235b843c749SSergey Zigachev /* Load the HW buffer with the Data to be sent.
236b843c749SSergey Zigachev * This is relevant for write operation.
237b843c749SSergey Zigachev * For read, the data recived data will be
238b843c749SSergey Zigachev * processed in process_channel_reply().
239b843c749SSergey Zigachev */
240b843c749SSergey Zigachev uint32_t i = 0;
241b843c749SSergey Zigachev
242b843c749SSergey Zigachev while (i < request->length) {
243b843c749SSergey Zigachev value = REG_SET(AUX_SW_DATA, value,
244b843c749SSergey Zigachev AUX_SW_DATA, request->data[i]);
245b843c749SSergey Zigachev
246b843c749SSergey Zigachev ++i;
247b843c749SSergey Zigachev }
248b843c749SSergey Zigachev }
249b843c749SSergey Zigachev
250b843c749SSergey Zigachev REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
251b843c749SSergey Zigachev }
252b843c749SSergey Zigachev
read_channel_reply(struct aux_engine * engine,uint32_t size,uint8_t * buffer,uint8_t * reply_result,uint32_t * sw_status)253b843c749SSergey Zigachev static int read_channel_reply(struct aux_engine *engine, uint32_t size,
254b843c749SSergey Zigachev uint8_t *buffer, uint8_t *reply_result,
255b843c749SSergey Zigachev uint32_t *sw_status)
256b843c749SSergey Zigachev {
257b843c749SSergey Zigachev struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
258b843c749SSergey Zigachev uint32_t bytes_replied;
259b843c749SSergey Zigachev uint32_t reply_result_32;
260b843c749SSergey Zigachev
261b843c749SSergey Zigachev *sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT,
262b843c749SSergey Zigachev &bytes_replied);
263b843c749SSergey Zigachev
264b843c749SSergey Zigachev /* In case HPD is LOW, exit AUX transaction */
265b843c749SSergey Zigachev if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
266b843c749SSergey Zigachev return -1;
267b843c749SSergey Zigachev
268b843c749SSergey Zigachev /* Need at least the status byte */
269b843c749SSergey Zigachev if (!bytes_replied)
270b843c749SSergey Zigachev return -1;
271b843c749SSergey Zigachev
272b843c749SSergey Zigachev REG_UPDATE_1BY1_3(AUX_SW_DATA,
273b843c749SSergey Zigachev AUX_SW_INDEX, 0,
274b843c749SSergey Zigachev AUX_SW_AUTOINCREMENT_DISABLE, 1,
275b843c749SSergey Zigachev AUX_SW_DATA_RW, 1);
276b843c749SSergey Zigachev
277b843c749SSergey Zigachev REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32);
278b843c749SSergey Zigachev reply_result_32 = reply_result_32 >> 4;
279b843c749SSergey Zigachev *reply_result = (uint8_t)reply_result_32;
280b843c749SSergey Zigachev
281b843c749SSergey Zigachev if (reply_result_32 == 0) { /* ACK */
282b843c749SSergey Zigachev uint32_t i = 0;
283b843c749SSergey Zigachev
284b843c749SSergey Zigachev /* First byte was already used to get the command status */
285b843c749SSergey Zigachev --bytes_replied;
286b843c749SSergey Zigachev
287b843c749SSergey Zigachev /* Do not overflow buffer */
288b843c749SSergey Zigachev if (bytes_replied > size)
289b843c749SSergey Zigachev return -1;
290b843c749SSergey Zigachev
291b843c749SSergey Zigachev while (i < bytes_replied) {
292b843c749SSergey Zigachev uint32_t aux_sw_data_val;
293b843c749SSergey Zigachev
294b843c749SSergey Zigachev REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
295b843c749SSergey Zigachev buffer[i] = aux_sw_data_val;
296b843c749SSergey Zigachev ++i;
297b843c749SSergey Zigachev }
298b843c749SSergey Zigachev
299b843c749SSergey Zigachev return i;
300b843c749SSergey Zigachev }
301b843c749SSergey Zigachev
302b843c749SSergey Zigachev return 0;
303b843c749SSergey Zigachev }
304b843c749SSergey Zigachev
process_channel_reply(struct aux_engine * engine,struct aux_reply_transaction_data * reply)305b843c749SSergey Zigachev static void process_channel_reply(
306b843c749SSergey Zigachev struct aux_engine *engine,
307b843c749SSergey Zigachev struct aux_reply_transaction_data *reply)
308b843c749SSergey Zigachev {
309b843c749SSergey Zigachev int bytes_replied;
310b843c749SSergey Zigachev uint8_t reply_result;
311b843c749SSergey Zigachev uint32_t sw_status;
312b843c749SSergey Zigachev
313b843c749SSergey Zigachev bytes_replied = read_channel_reply(engine, reply->length, reply->data,
314b843c749SSergey Zigachev &reply_result, &sw_status);
315b843c749SSergey Zigachev
316b843c749SSergey Zigachev /* in case HPD is LOW, exit AUX transaction */
317b843c749SSergey Zigachev if ((sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
318b843c749SSergey Zigachev reply->status = AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
319b843c749SSergey Zigachev return;
320b843c749SSergey Zigachev }
321b843c749SSergey Zigachev
322b843c749SSergey Zigachev if (bytes_replied < 0) {
323b843c749SSergey Zigachev /* Need to handle an error case...
324b843c749SSergey Zigachev * Hopefully, upper layer function won't call this function if
325b843c749SSergey Zigachev * the number of bytes in the reply was 0, because there was
326b843c749SSergey Zigachev * surely an error that was asserted that should have been
327b843c749SSergey Zigachev * handled for hot plug case, this could happens
328b843c749SSergey Zigachev */
329b843c749SSergey Zigachev if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
330b843c749SSergey Zigachev reply->status = AUX_TRANSACTION_REPLY_INVALID;
331b843c749SSergey Zigachev ASSERT_CRITICAL(false);
332b843c749SSergey Zigachev return;
333b843c749SSergey Zigachev }
334b843c749SSergey Zigachev } else {
335b843c749SSergey Zigachev
336b843c749SSergey Zigachev switch (reply_result) {
337b843c749SSergey Zigachev case 0: /* ACK */
338b843c749SSergey Zigachev reply->status = AUX_TRANSACTION_REPLY_AUX_ACK;
339b843c749SSergey Zigachev break;
340b843c749SSergey Zigachev case 1: /* NACK */
341b843c749SSergey Zigachev reply->status = AUX_TRANSACTION_REPLY_AUX_NACK;
342b843c749SSergey Zigachev break;
343b843c749SSergey Zigachev case 2: /* DEFER */
344b843c749SSergey Zigachev reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER;
345b843c749SSergey Zigachev break;
346b843c749SSergey Zigachev case 4: /* AUX ACK / I2C NACK */
347b843c749SSergey Zigachev reply->status = AUX_TRANSACTION_REPLY_I2C_NACK;
348b843c749SSergey Zigachev break;
349b843c749SSergey Zigachev case 8: /* AUX ACK / I2C DEFER */
350b843c749SSergey Zigachev reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER;
351b843c749SSergey Zigachev break;
352b843c749SSergey Zigachev default:
353b843c749SSergey Zigachev reply->status = AUX_TRANSACTION_REPLY_INVALID;
354b843c749SSergey Zigachev }
355b843c749SSergey Zigachev }
356b843c749SSergey Zigachev }
357b843c749SSergey Zigachev
get_channel_status(struct aux_engine * engine,uint8_t * returned_bytes)358b843c749SSergey Zigachev static enum aux_channel_operation_result get_channel_status(
359b843c749SSergey Zigachev struct aux_engine *engine,
360b843c749SSergey Zigachev uint8_t *returned_bytes)
361b843c749SSergey Zigachev {
362b843c749SSergey Zigachev struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
363b843c749SSergey Zigachev
364b843c749SSergey Zigachev uint32_t value;
365b843c749SSergey Zigachev
366b843c749SSergey Zigachev if (returned_bytes == NULL) {
367b843c749SSergey Zigachev /*caller pass NULL pointer*/
368b843c749SSergey Zigachev ASSERT_CRITICAL(false);
369b843c749SSergey Zigachev return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN;
370b843c749SSergey Zigachev }
371b843c749SSergey Zigachev *returned_bytes = 0;
372b843c749SSergey Zigachev
373b843c749SSergey Zigachev /* poll to make sure that SW_DONE is asserted */
374b843c749SSergey Zigachev value = REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1,
375b843c749SSergey Zigachev 10, aux110->timeout_period/10);
376b843c749SSergey Zigachev
377b843c749SSergey Zigachev /* in case HPD is LOW, exit AUX transaction */
378b843c749SSergey Zigachev if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
379b843c749SSergey Zigachev return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
380b843c749SSergey Zigachev
381b843c749SSergey Zigachev /* Note that the following bits are set in 'status.bits'
382b843c749SSergey Zigachev * during CTS 4.2.1.2 (FW 3.3.1):
383b843c749SSergey Zigachev * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP,
384b843c749SSergey Zigachev * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H.
385b843c749SSergey Zigachev *
386b843c749SSergey Zigachev * AUX_SW_RX_MIN_COUNT_VIOL is an internal,
387b843c749SSergey Zigachev * HW debugging bit and should be ignored.
388b843c749SSergey Zigachev */
389b843c749SSergey Zigachev if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) {
390b843c749SSergey Zigachev if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) ||
391b843c749SSergey Zigachev (value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK))
392b843c749SSergey Zigachev return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
393b843c749SSergey Zigachev
394b843c749SSergey Zigachev else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) ||
395b843c749SSergey Zigachev (value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) ||
396b843c749SSergey Zigachev (value &
397b843c749SSergey Zigachev AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) ||
398b843c749SSergey Zigachev (value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK))
399b843c749SSergey Zigachev return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
400b843c749SSergey Zigachev
401b843c749SSergey Zigachev *returned_bytes = get_reg_field_value(value,
402b843c749SSergey Zigachev AUX_SW_STATUS,
403b843c749SSergey Zigachev AUX_SW_REPLY_BYTE_COUNT);
404b843c749SSergey Zigachev
405b843c749SSergey Zigachev if (*returned_bytes == 0)
406b843c749SSergey Zigachev return
407b843c749SSergey Zigachev AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
408b843c749SSergey Zigachev else {
409b843c749SSergey Zigachev *returned_bytes -= 1;
410b843c749SSergey Zigachev return AUX_CHANNEL_OPERATION_SUCCEEDED;
411b843c749SSergey Zigachev }
412b843c749SSergey Zigachev } else {
413b843c749SSergey Zigachev /*time_elapsed >= aux_engine->timeout_period
414b843c749SSergey Zigachev * AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point
415b843c749SSergey Zigachev */
416b843c749SSergey Zigachev ASSERT_CRITICAL(false);
417b843c749SSergey Zigachev return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
418b843c749SSergey Zigachev }
419b843c749SSergey Zigachev }
process_read_reply(struct aux_engine * engine,struct read_command_context * ctx)420b843c749SSergey Zigachev static void process_read_reply(
421b843c749SSergey Zigachev struct aux_engine *engine,
422b843c749SSergey Zigachev struct read_command_context *ctx)
423b843c749SSergey Zigachev {
424b843c749SSergey Zigachev engine->funcs->process_channel_reply(engine, &ctx->reply);
425b843c749SSergey Zigachev
426b843c749SSergey Zigachev switch (ctx->reply.status) {
427b843c749SSergey Zigachev case AUX_TRANSACTION_REPLY_AUX_ACK:
428b843c749SSergey Zigachev ctx->defer_retry_aux = 0;
429b843c749SSergey Zigachev if (ctx->returned_byte > ctx->current_read_length) {
430b843c749SSergey Zigachev ctx->status =
431b843c749SSergey Zigachev I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
432b843c749SSergey Zigachev ctx->operation_succeeded = false;
433b843c749SSergey Zigachev } else if (ctx->returned_byte < ctx->current_read_length) {
434b843c749SSergey Zigachev ctx->current_read_length -= ctx->returned_byte;
435b843c749SSergey Zigachev
436b843c749SSergey Zigachev ctx->offset += ctx->returned_byte;
437b843c749SSergey Zigachev
438b843c749SSergey Zigachev ++ctx->invalid_reply_retry_aux_on_ack;
439b843c749SSergey Zigachev
440b843c749SSergey Zigachev if (ctx->invalid_reply_retry_aux_on_ack >
441b843c749SSergey Zigachev AUX_INVALID_REPLY_RETRY_COUNTER) {
442b843c749SSergey Zigachev ctx->status =
443b843c749SSergey Zigachev I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
444b843c749SSergey Zigachev ctx->operation_succeeded = false;
445b843c749SSergey Zigachev }
446b843c749SSergey Zigachev } else {
447b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
448b843c749SSergey Zigachev ctx->transaction_complete = true;
449b843c749SSergey Zigachev ctx->operation_succeeded = true;
450b843c749SSergey Zigachev }
451b843c749SSergey Zigachev break;
452b843c749SSergey Zigachev case AUX_TRANSACTION_REPLY_AUX_NACK:
453b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
454b843c749SSergey Zigachev ctx->operation_succeeded = false;
455b843c749SSergey Zigachev break;
456b843c749SSergey Zigachev case AUX_TRANSACTION_REPLY_AUX_DEFER:
457b843c749SSergey Zigachev ++ctx->defer_retry_aux;
458b843c749SSergey Zigachev
459b843c749SSergey Zigachev if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) {
460b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
461b843c749SSergey Zigachev ctx->operation_succeeded = false;
462b843c749SSergey Zigachev }
463b843c749SSergey Zigachev break;
464b843c749SSergey Zigachev case AUX_TRANSACTION_REPLY_I2C_DEFER:
465b843c749SSergey Zigachev ctx->defer_retry_aux = 0;
466b843c749SSergey Zigachev
467b843c749SSergey Zigachev ++ctx->defer_retry_i2c;
468b843c749SSergey Zigachev
469b843c749SSergey Zigachev if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) {
470b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
471b843c749SSergey Zigachev ctx->operation_succeeded = false;
472b843c749SSergey Zigachev }
473b843c749SSergey Zigachev break;
474b843c749SSergey Zigachev case AUX_TRANSACTION_REPLY_HPD_DISCON:
475b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
476b843c749SSergey Zigachev ctx->operation_succeeded = false;
477b843c749SSergey Zigachev break;
478b843c749SSergey Zigachev default:
479b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
480b843c749SSergey Zigachev ctx->operation_succeeded = false;
481b843c749SSergey Zigachev }
482b843c749SSergey Zigachev }
process_read_request(struct aux_engine * engine,struct read_command_context * ctx)483b843c749SSergey Zigachev static void process_read_request(
484b843c749SSergey Zigachev struct aux_engine *engine,
485b843c749SSergey Zigachev struct read_command_context *ctx)
486b843c749SSergey Zigachev {
487b843c749SSergey Zigachev enum aux_channel_operation_result operation_result;
488b843c749SSergey Zigachev
489b843c749SSergey Zigachev engine->funcs->submit_channel_request(engine, &ctx->request);
490b843c749SSergey Zigachev
491b843c749SSergey Zigachev operation_result = engine->funcs->get_channel_status(
492b843c749SSergey Zigachev engine, &ctx->returned_byte);
493b843c749SSergey Zigachev
494b843c749SSergey Zigachev switch (operation_result) {
495b843c749SSergey Zigachev case AUX_CHANNEL_OPERATION_SUCCEEDED:
496b843c749SSergey Zigachev if (ctx->returned_byte > ctx->current_read_length) {
497b843c749SSergey Zigachev ctx->status =
498b843c749SSergey Zigachev I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
499b843c749SSergey Zigachev ctx->operation_succeeded = false;
500b843c749SSergey Zigachev } else {
501b843c749SSergey Zigachev ctx->timed_out_retry_aux = 0;
502b843c749SSergey Zigachev ctx->invalid_reply_retry_aux = 0;
503b843c749SSergey Zigachev
504b843c749SSergey Zigachev ctx->reply.length = ctx->returned_byte;
505b843c749SSergey Zigachev ctx->reply.data = ctx->buffer;
506b843c749SSergey Zigachev
507b843c749SSergey Zigachev process_read_reply(engine, ctx);
508b843c749SSergey Zigachev }
509b843c749SSergey Zigachev break;
510b843c749SSergey Zigachev case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
511b843c749SSergey Zigachev ++ctx->invalid_reply_retry_aux;
512b843c749SSergey Zigachev
513b843c749SSergey Zigachev if (ctx->invalid_reply_retry_aux >
514b843c749SSergey Zigachev AUX_INVALID_REPLY_RETRY_COUNTER) {
515b843c749SSergey Zigachev ctx->status =
516b843c749SSergey Zigachev I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
517b843c749SSergey Zigachev ctx->operation_succeeded = false;
518b843c749SSergey Zigachev } else
519b843c749SSergey Zigachev udelay(400);
520b843c749SSergey Zigachev break;
521b843c749SSergey Zigachev case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
522b843c749SSergey Zigachev ++ctx->timed_out_retry_aux;
523b843c749SSergey Zigachev
524b843c749SSergey Zigachev if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
525b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
526b843c749SSergey Zigachev ctx->operation_succeeded = false;
527b843c749SSergey Zigachev } else {
528b843c749SSergey Zigachev /* DP 1.2a, table 2-58:
529b843c749SSergey Zigachev * "S3: AUX Request CMD PENDING:
530b843c749SSergey Zigachev * retry 3 times, with 400usec wait on each"
531b843c749SSergey Zigachev * The HW timeout is set to 550usec,
532b843c749SSergey Zigachev * so we should not wait here
533b843c749SSergey Zigachev */
534b843c749SSergey Zigachev }
535b843c749SSergey Zigachev break;
536b843c749SSergey Zigachev case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
537b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
538b843c749SSergey Zigachev ctx->operation_succeeded = false;
539b843c749SSergey Zigachev break;
540b843c749SSergey Zigachev default:
541b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
542b843c749SSergey Zigachev ctx->operation_succeeded = false;
543b843c749SSergey Zigachev }
544b843c749SSergey Zigachev }
read_command(struct aux_engine * engine,struct i2caux_transaction_request * request,bool middle_of_transaction)545b843c749SSergey Zigachev static bool read_command(
546b843c749SSergey Zigachev struct aux_engine *engine,
547b843c749SSergey Zigachev struct i2caux_transaction_request *request,
548b843c749SSergey Zigachev bool middle_of_transaction)
549b843c749SSergey Zigachev {
550b843c749SSergey Zigachev struct read_command_context ctx;
551b843c749SSergey Zigachev
552b843c749SSergey Zigachev ctx.buffer = request->payload.data;
553b843c749SSergey Zigachev ctx.current_read_length = request->payload.length;
554b843c749SSergey Zigachev ctx.offset = 0;
555b843c749SSergey Zigachev ctx.timed_out_retry_aux = 0;
556b843c749SSergey Zigachev ctx.invalid_reply_retry_aux = 0;
557b843c749SSergey Zigachev ctx.defer_retry_aux = 0;
558b843c749SSergey Zigachev ctx.defer_retry_i2c = 0;
559b843c749SSergey Zigachev ctx.invalid_reply_retry_aux_on_ack = 0;
560b843c749SSergey Zigachev ctx.transaction_complete = false;
561b843c749SSergey Zigachev ctx.operation_succeeded = true;
562b843c749SSergey Zigachev
563b843c749SSergey Zigachev if (request->payload.address_space ==
564b843c749SSergey Zigachev I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
565b843c749SSergey Zigachev ctx.request.type = AUX_TRANSACTION_TYPE_DP;
566b843c749SSergey Zigachev ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_READ;
567b843c749SSergey Zigachev ctx.request.address = request->payload.address;
568b843c749SSergey Zigachev } else if (request->payload.address_space ==
569b843c749SSergey Zigachev I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
570b843c749SSergey Zigachev ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
571b843c749SSergey Zigachev ctx.request.action = middle_of_transaction ?
572b843c749SSergey Zigachev I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
573b843c749SSergey Zigachev I2CAUX_TRANSACTION_ACTION_I2C_READ;
574b843c749SSergey Zigachev ctx.request.address = request->payload.address >> 1;
575b843c749SSergey Zigachev } else {
576b843c749SSergey Zigachev /* in DAL2, there was no return in such case */
577b843c749SSergey Zigachev BREAK_TO_DEBUGGER();
578b843c749SSergey Zigachev return false;
579b843c749SSergey Zigachev }
580b843c749SSergey Zigachev
581b843c749SSergey Zigachev ctx.request.delay = 0;
582b843c749SSergey Zigachev
583b843c749SSergey Zigachev do {
584b843c749SSergey Zigachev memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length);
585b843c749SSergey Zigachev
586b843c749SSergey Zigachev ctx.request.data = ctx.buffer + ctx.offset;
587b843c749SSergey Zigachev ctx.request.length = ctx.current_read_length;
588b843c749SSergey Zigachev
589b843c749SSergey Zigachev process_read_request(engine, &ctx);
590b843c749SSergey Zigachev
591b843c749SSergey Zigachev request->status = ctx.status;
592b843c749SSergey Zigachev
593b843c749SSergey Zigachev if (ctx.operation_succeeded && !ctx.transaction_complete)
594b843c749SSergey Zigachev if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
595b843c749SSergey Zigachev msleep(engine->delay);
596b843c749SSergey Zigachev } while (ctx.operation_succeeded && !ctx.transaction_complete);
597b843c749SSergey Zigachev
598b843c749SSergey Zigachev if (request->payload.address_space ==
599b843c749SSergey Zigachev I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
600b843c749SSergey Zigachev DC_LOG_I2C_AUX("READ: addr:0x%x value:0x%x Result:%d",
601b843c749SSergey Zigachev request->payload.address,
602b843c749SSergey Zigachev request->payload.data[0],
603b843c749SSergey Zigachev ctx.operation_succeeded);
604b843c749SSergey Zigachev }
605b843c749SSergey Zigachev
606b843c749SSergey Zigachev return ctx.operation_succeeded;
607b843c749SSergey Zigachev }
608b843c749SSergey Zigachev
process_write_reply(struct aux_engine * engine,struct write_command_context * ctx)609b843c749SSergey Zigachev static void process_write_reply(
610b843c749SSergey Zigachev struct aux_engine *engine,
611b843c749SSergey Zigachev struct write_command_context *ctx)
612b843c749SSergey Zigachev {
613b843c749SSergey Zigachev engine->funcs->process_channel_reply(engine, &ctx->reply);
614b843c749SSergey Zigachev
615b843c749SSergey Zigachev switch (ctx->reply.status) {
616b843c749SSergey Zigachev case AUX_TRANSACTION_REPLY_AUX_ACK:
617b843c749SSergey Zigachev ctx->operation_succeeded = true;
618b843c749SSergey Zigachev
619b843c749SSergey Zigachev if (ctx->returned_byte) {
620b843c749SSergey Zigachev ctx->request.action = ctx->mot ?
621b843c749SSergey Zigachev I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
622b843c749SSergey Zigachev I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
623b843c749SSergey Zigachev
624b843c749SSergey Zigachev ctx->current_write_length = 0;
625b843c749SSergey Zigachev
626b843c749SSergey Zigachev ++ctx->ack_m_retry;
627b843c749SSergey Zigachev
628b843c749SSergey Zigachev if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) {
629b843c749SSergey Zigachev ctx->status =
630b843c749SSergey Zigachev I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
631b843c749SSergey Zigachev ctx->operation_succeeded = false;
632b843c749SSergey Zigachev } else
633b843c749SSergey Zigachev udelay(300);
634b843c749SSergey Zigachev } else {
635b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
636b843c749SSergey Zigachev ctx->defer_retry_aux = 0;
637b843c749SSergey Zigachev ctx->ack_m_retry = 0;
638b843c749SSergey Zigachev ctx->transaction_complete = true;
639b843c749SSergey Zigachev }
640b843c749SSergey Zigachev break;
641b843c749SSergey Zigachev case AUX_TRANSACTION_REPLY_AUX_NACK:
642b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
643b843c749SSergey Zigachev ctx->operation_succeeded = false;
644b843c749SSergey Zigachev break;
645b843c749SSergey Zigachev case AUX_TRANSACTION_REPLY_AUX_DEFER:
646b843c749SSergey Zigachev ++ctx->defer_retry_aux;
647b843c749SSergey Zigachev
648b843c749SSergey Zigachev if (ctx->defer_retry_aux > ctx->max_defer_retry) {
649b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
650b843c749SSergey Zigachev ctx->operation_succeeded = false;
651b843c749SSergey Zigachev }
652b843c749SSergey Zigachev break;
653b843c749SSergey Zigachev case AUX_TRANSACTION_REPLY_I2C_DEFER:
654b843c749SSergey Zigachev ctx->defer_retry_aux = 0;
655b843c749SSergey Zigachev ctx->current_write_length = 0;
656b843c749SSergey Zigachev
657b843c749SSergey Zigachev ctx->request.action = ctx->mot ?
658b843c749SSergey Zigachev I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
659b843c749SSergey Zigachev I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
660b843c749SSergey Zigachev
661b843c749SSergey Zigachev ++ctx->defer_retry_i2c;
662b843c749SSergey Zigachev
663b843c749SSergey Zigachev if (ctx->defer_retry_i2c > ctx->max_defer_retry) {
664b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
665b843c749SSergey Zigachev ctx->operation_succeeded = false;
666b843c749SSergey Zigachev }
667b843c749SSergey Zigachev break;
668b843c749SSergey Zigachev case AUX_TRANSACTION_REPLY_HPD_DISCON:
669b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
670b843c749SSergey Zigachev ctx->operation_succeeded = false;
671b843c749SSergey Zigachev break;
672b843c749SSergey Zigachev default:
673b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
674b843c749SSergey Zigachev ctx->operation_succeeded = false;
675b843c749SSergey Zigachev }
676b843c749SSergey Zigachev }
process_write_request(struct aux_engine * engine,struct write_command_context * ctx)677b843c749SSergey Zigachev static void process_write_request(
678b843c749SSergey Zigachev struct aux_engine *engine,
679b843c749SSergey Zigachev struct write_command_context *ctx)
680b843c749SSergey Zigachev {
681b843c749SSergey Zigachev enum aux_channel_operation_result operation_result;
682b843c749SSergey Zigachev
683b843c749SSergey Zigachev engine->funcs->submit_channel_request(engine, &ctx->request);
684b843c749SSergey Zigachev
685b843c749SSergey Zigachev operation_result = engine->funcs->get_channel_status(
686b843c749SSergey Zigachev engine, &ctx->returned_byte);
687b843c749SSergey Zigachev
688b843c749SSergey Zigachev switch (operation_result) {
689b843c749SSergey Zigachev case AUX_CHANNEL_OPERATION_SUCCEEDED:
690b843c749SSergey Zigachev ctx->timed_out_retry_aux = 0;
691b843c749SSergey Zigachev ctx->invalid_reply_retry_aux = 0;
692b843c749SSergey Zigachev
693b843c749SSergey Zigachev ctx->reply.length = ctx->returned_byte;
694b843c749SSergey Zigachev ctx->reply.data = ctx->reply_data;
695b843c749SSergey Zigachev
696b843c749SSergey Zigachev process_write_reply(engine, ctx);
697b843c749SSergey Zigachev break;
698b843c749SSergey Zigachev case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
699b843c749SSergey Zigachev ++ctx->invalid_reply_retry_aux;
700b843c749SSergey Zigachev
701b843c749SSergey Zigachev if (ctx->invalid_reply_retry_aux >
702b843c749SSergey Zigachev AUX_INVALID_REPLY_RETRY_COUNTER) {
703b843c749SSergey Zigachev ctx->status =
704b843c749SSergey Zigachev I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
705b843c749SSergey Zigachev ctx->operation_succeeded = false;
706b843c749SSergey Zigachev } else
707b843c749SSergey Zigachev udelay(400);
708b843c749SSergey Zigachev break;
709b843c749SSergey Zigachev case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
710b843c749SSergey Zigachev ++ctx->timed_out_retry_aux;
711b843c749SSergey Zigachev
712b843c749SSergey Zigachev if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
713b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
714b843c749SSergey Zigachev ctx->operation_succeeded = false;
715b843c749SSergey Zigachev } else {
716b843c749SSergey Zigachev /* DP 1.2a, table 2-58:
717b843c749SSergey Zigachev * "S3: AUX Request CMD PENDING:
718b843c749SSergey Zigachev * retry 3 times, with 400usec wait on each"
719b843c749SSergey Zigachev * The HW timeout is set to 550usec,
720b843c749SSergey Zigachev * so we should not wait here
721b843c749SSergey Zigachev */
722b843c749SSergey Zigachev }
723b843c749SSergey Zigachev break;
724b843c749SSergey Zigachev case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
725b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
726b843c749SSergey Zigachev ctx->operation_succeeded = false;
727b843c749SSergey Zigachev break;
728b843c749SSergey Zigachev default:
729b843c749SSergey Zigachev ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
730b843c749SSergey Zigachev ctx->operation_succeeded = false;
731b843c749SSergey Zigachev }
732b843c749SSergey Zigachev }
write_command(struct aux_engine * engine,struct i2caux_transaction_request * request,bool middle_of_transaction)733b843c749SSergey Zigachev static bool write_command(
734b843c749SSergey Zigachev struct aux_engine *engine,
735b843c749SSergey Zigachev struct i2caux_transaction_request *request,
736b843c749SSergey Zigachev bool middle_of_transaction)
737b843c749SSergey Zigachev {
738b843c749SSergey Zigachev struct write_command_context ctx;
739b843c749SSergey Zigachev
740b843c749SSergey Zigachev ctx.mot = middle_of_transaction;
741b843c749SSergey Zigachev ctx.buffer = request->payload.data;
742b843c749SSergey Zigachev ctx.current_write_length = request->payload.length;
743b843c749SSergey Zigachev ctx.timed_out_retry_aux = 0;
744b843c749SSergey Zigachev ctx.invalid_reply_retry_aux = 0;
745b843c749SSergey Zigachev ctx.defer_retry_aux = 0;
746b843c749SSergey Zigachev ctx.defer_retry_i2c = 0;
747b843c749SSergey Zigachev ctx.ack_m_retry = 0;
748b843c749SSergey Zigachev ctx.transaction_complete = false;
749b843c749SSergey Zigachev ctx.operation_succeeded = true;
750b843c749SSergey Zigachev
751b843c749SSergey Zigachev if (request->payload.address_space ==
752b843c749SSergey Zigachev I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
753b843c749SSergey Zigachev ctx.request.type = AUX_TRANSACTION_TYPE_DP;
754b843c749SSergey Zigachev ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_WRITE;
755b843c749SSergey Zigachev ctx.request.address = request->payload.address;
756b843c749SSergey Zigachev } else if (request->payload.address_space ==
757b843c749SSergey Zigachev I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
758b843c749SSergey Zigachev ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
759b843c749SSergey Zigachev ctx.request.action = middle_of_transaction ?
760b843c749SSergey Zigachev I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
761b843c749SSergey Zigachev I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
762b843c749SSergey Zigachev ctx.request.address = request->payload.address >> 1;
763b843c749SSergey Zigachev } else {
764b843c749SSergey Zigachev /* in DAL2, there was no return in such case */
765b843c749SSergey Zigachev BREAK_TO_DEBUGGER();
766b843c749SSergey Zigachev return false;
767b843c749SSergey Zigachev }
768b843c749SSergey Zigachev
769b843c749SSergey Zigachev ctx.request.delay = 0;
770b843c749SSergey Zigachev
771b843c749SSergey Zigachev ctx.max_defer_retry =
772b843c749SSergey Zigachev (engine->max_defer_write_retry > AUX_DEFER_RETRY_COUNTER) ?
773b843c749SSergey Zigachev engine->max_defer_write_retry : AUX_DEFER_RETRY_COUNTER;
774b843c749SSergey Zigachev
775b843c749SSergey Zigachev do {
776b843c749SSergey Zigachev ctx.request.data = ctx.buffer;
777b843c749SSergey Zigachev ctx.request.length = ctx.current_write_length;
778b843c749SSergey Zigachev
779b843c749SSergey Zigachev process_write_request(engine, &ctx);
780b843c749SSergey Zigachev
781b843c749SSergey Zigachev request->status = ctx.status;
782b843c749SSergey Zigachev
783b843c749SSergey Zigachev if (ctx.operation_succeeded && !ctx.transaction_complete)
784b843c749SSergey Zigachev if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
785b843c749SSergey Zigachev msleep(engine->delay);
786b843c749SSergey Zigachev } while (ctx.operation_succeeded && !ctx.transaction_complete);
787b843c749SSergey Zigachev
788b843c749SSergey Zigachev if (request->payload.address_space ==
789b843c749SSergey Zigachev I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
790b843c749SSergey Zigachev DC_LOG_I2C_AUX("WRITE: addr:0x%x value:0x%x Result:%d",
791b843c749SSergey Zigachev request->payload.address,
792b843c749SSergey Zigachev request->payload.data[0],
793b843c749SSergey Zigachev ctx.operation_succeeded);
794b843c749SSergey Zigachev }
795b843c749SSergey Zigachev
796b843c749SSergey Zigachev return ctx.operation_succeeded;
797b843c749SSergey Zigachev }
end_of_transaction_command(struct aux_engine * engine,struct i2caux_transaction_request * request)798b843c749SSergey Zigachev static bool end_of_transaction_command(
799b843c749SSergey Zigachev struct aux_engine *engine,
800b843c749SSergey Zigachev struct i2caux_transaction_request *request)
801b843c749SSergey Zigachev {
802b843c749SSergey Zigachev struct i2caux_transaction_request dummy_request;
803b843c749SSergey Zigachev uint8_t dummy_data;
804b843c749SSergey Zigachev
805b843c749SSergey Zigachev /* [tcheng] We only need to send the stop (read with MOT = 0)
806b843c749SSergey Zigachev * for I2C-over-Aux, not native AUX
807b843c749SSergey Zigachev */
808b843c749SSergey Zigachev
809b843c749SSergey Zigachev if (request->payload.address_space !=
810b843c749SSergey Zigachev I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C)
811b843c749SSergey Zigachev return false;
812b843c749SSergey Zigachev
813b843c749SSergey Zigachev dummy_request.operation = request->operation;
814b843c749SSergey Zigachev dummy_request.payload.address_space = request->payload.address_space;
815b843c749SSergey Zigachev dummy_request.payload.address = request->payload.address;
816b843c749SSergey Zigachev
817b843c749SSergey Zigachev /*
818b843c749SSergey Zigachev * Add a dummy byte due to some receiver quirk
819b843c749SSergey Zigachev * where one byte is sent along with MOT = 0.
820b843c749SSergey Zigachev * Ideally this should be 0.
821b843c749SSergey Zigachev */
822b843c749SSergey Zigachev
823b843c749SSergey Zigachev dummy_request.payload.length = 0;
824b843c749SSergey Zigachev dummy_request.payload.data = &dummy_data;
825b843c749SSergey Zigachev
826b843c749SSergey Zigachev if (request->operation == I2CAUX_TRANSACTION_READ)
827b843c749SSergey Zigachev return read_command(engine, &dummy_request, false);
828b843c749SSergey Zigachev else
829b843c749SSergey Zigachev return write_command(engine, &dummy_request, false);
830b843c749SSergey Zigachev
831b843c749SSergey Zigachev /* according Syed, it does not need now DoDummyMOT */
832b843c749SSergey Zigachev }
submit_request(struct aux_engine * engine,struct i2caux_transaction_request * request,bool middle_of_transaction)833b843c749SSergey Zigachev static bool submit_request(
834b843c749SSergey Zigachev struct aux_engine *engine,
835b843c749SSergey Zigachev struct i2caux_transaction_request *request,
836b843c749SSergey Zigachev bool middle_of_transaction)
837b843c749SSergey Zigachev {
838b843c749SSergey Zigachev
839b843c749SSergey Zigachev bool result;
840b843c749SSergey Zigachev bool mot_used = true;
841b843c749SSergey Zigachev
842b843c749SSergey Zigachev switch (request->operation) {
843b843c749SSergey Zigachev case I2CAUX_TRANSACTION_READ:
844b843c749SSergey Zigachev result = read_command(engine, request, mot_used);
845b843c749SSergey Zigachev break;
846b843c749SSergey Zigachev case I2CAUX_TRANSACTION_WRITE:
847b843c749SSergey Zigachev result = write_command(engine, request, mot_used);
848b843c749SSergey Zigachev break;
849b843c749SSergey Zigachev default:
850b843c749SSergey Zigachev result = false;
851b843c749SSergey Zigachev }
852b843c749SSergey Zigachev
853b843c749SSergey Zigachev /* [tcheng]
854b843c749SSergey Zigachev * need to send stop for the last transaction to free up the AUX
855b843c749SSergey Zigachev * if the above command fails, this would be the last transaction
856b843c749SSergey Zigachev */
857b843c749SSergey Zigachev
858b843c749SSergey Zigachev if (!middle_of_transaction || !result)
859b843c749SSergey Zigachev end_of_transaction_command(engine, request);
860b843c749SSergey Zigachev
861b843c749SSergey Zigachev /* mask AUX interrupt */
862b843c749SSergey Zigachev
863b843c749SSergey Zigachev return result;
864b843c749SSergey Zigachev }
865*78973132SSergey Zigachev
866*78973132SSergey Zigachev static
get_engine_type(const struct aux_engine * engine)867b843c749SSergey Zigachev enum i2caux_engine_type get_engine_type(
868b843c749SSergey Zigachev const struct aux_engine *engine)
869b843c749SSergey Zigachev {
870b843c749SSergey Zigachev return I2CAUX_ENGINE_TYPE_AUX;
871b843c749SSergey Zigachev }
872b843c749SSergey Zigachev
acquire(struct aux_engine * engine,struct ddc * ddc)873b843c749SSergey Zigachev static bool acquire(
874b843c749SSergey Zigachev struct aux_engine *engine,
875b843c749SSergey Zigachev struct ddc *ddc)
876b843c749SSergey Zigachev {
877b843c749SSergey Zigachev
878b843c749SSergey Zigachev enum gpio_result result;
879b843c749SSergey Zigachev
880b843c749SSergey Zigachev if (engine->funcs->is_engine_available) {
881b843c749SSergey Zigachev /*check whether SW could use the engine*/
882b843c749SSergey Zigachev if (!engine->funcs->is_engine_available(engine))
883b843c749SSergey Zigachev return false;
884b843c749SSergey Zigachev }
885b843c749SSergey Zigachev
886b843c749SSergey Zigachev result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
887b843c749SSergey Zigachev GPIO_DDC_CONFIG_TYPE_MODE_AUX);
888b843c749SSergey Zigachev
889b843c749SSergey Zigachev if (result != GPIO_RESULT_OK)
890b843c749SSergey Zigachev return false;
891b843c749SSergey Zigachev
892b843c749SSergey Zigachev if (!engine->funcs->acquire_engine(engine)) {
893b843c749SSergey Zigachev dal_ddc_close(ddc);
894b843c749SSergey Zigachev return false;
895b843c749SSergey Zigachev }
896b843c749SSergey Zigachev
897b843c749SSergey Zigachev engine->ddc = ddc;
898b843c749SSergey Zigachev
899b843c749SSergey Zigachev return true;
900b843c749SSergey Zigachev }
901b843c749SSergey Zigachev
902b843c749SSergey Zigachev static const struct aux_engine_funcs aux_engine_funcs = {
903b843c749SSergey Zigachev .acquire_engine = acquire_engine,
904b843c749SSergey Zigachev .submit_channel_request = submit_channel_request,
905b843c749SSergey Zigachev .process_channel_reply = process_channel_reply,
906b843c749SSergey Zigachev .read_channel_reply = read_channel_reply,
907b843c749SSergey Zigachev .get_channel_status = get_channel_status,
908b843c749SSergey Zigachev .is_engine_available = is_engine_available,
909b843c749SSergey Zigachev .release_engine = release_engine,
910b843c749SSergey Zigachev .destroy_engine = dce110_engine_destroy,
911b843c749SSergey Zigachev .submit_request = submit_request,
912b843c749SSergey Zigachev .get_engine_type = get_engine_type,
913b843c749SSergey Zigachev .acquire = acquire,
914b843c749SSergey Zigachev };
915b843c749SSergey Zigachev
dce110_engine_destroy(struct aux_engine ** engine)916b843c749SSergey Zigachev void dce110_engine_destroy(struct aux_engine **engine)
917b843c749SSergey Zigachev {
918b843c749SSergey Zigachev
919b843c749SSergey Zigachev struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine);
920b843c749SSergey Zigachev
921b843c749SSergey Zigachev kfree(engine110);
922b843c749SSergey Zigachev *engine = NULL;
923b843c749SSergey Zigachev
924b843c749SSergey Zigachev }
dce110_aux_engine_construct(struct aux_engine_dce110 * aux_engine110,struct dc_context * ctx,uint32_t inst,uint32_t timeout_period,const struct dce110_aux_registers * regs)925b843c749SSergey Zigachev struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
926b843c749SSergey Zigachev struct dc_context *ctx,
927b843c749SSergey Zigachev uint32_t inst,
928b843c749SSergey Zigachev uint32_t timeout_period,
929b843c749SSergey Zigachev const struct dce110_aux_registers *regs)
930b843c749SSergey Zigachev {
931b843c749SSergey Zigachev aux_engine110->base.ddc = NULL;
932b843c749SSergey Zigachev aux_engine110->base.ctx = ctx;
933b843c749SSergey Zigachev aux_engine110->base.delay = 0;
934b843c749SSergey Zigachev aux_engine110->base.max_defer_write_retry = 0;
935b843c749SSergey Zigachev aux_engine110->base.funcs = &aux_engine_funcs;
936b843c749SSergey Zigachev aux_engine110->base.inst = inst;
937b843c749SSergey Zigachev aux_engine110->timeout_period = timeout_period;
938b843c749SSergey Zigachev aux_engine110->regs = regs;
939b843c749SSergey Zigachev
940b843c749SSergey Zigachev return &aux_engine110->base;
941b843c749SSergey Zigachev }
942b843c749SSergey Zigachev
943