1*b843c749SSergey Zigachev /*
2*b843c749SSergey Zigachev  * Copyright 2012-15 Advanced Micro Devices, Inc.
3*b843c749SSergey Zigachev  *
4*b843c749SSergey Zigachev  * Permission is hereby granted, free of charge, to any person obtaining a
5*b843c749SSergey Zigachev  * copy of this software and associated documentation files (the "Software"),
6*b843c749SSergey Zigachev  * to deal in the Software without restriction, including without limitation
7*b843c749SSergey Zigachev  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*b843c749SSergey Zigachev  * and/or sell copies of the Software, and to permit persons to whom the
9*b843c749SSergey Zigachev  * Software is furnished to do so, subject to the following conditions:
10*b843c749SSergey Zigachev  *
11*b843c749SSergey Zigachev  * The above copyright notice and this permission notice shall be included in
12*b843c749SSergey Zigachev  * all copies or substantial portions of the Software.
13*b843c749SSergey Zigachev  *
14*b843c749SSergey Zigachev  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*b843c749SSergey Zigachev  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*b843c749SSergey Zigachev  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17*b843c749SSergey Zigachev  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18*b843c749SSergey Zigachev  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19*b843c749SSergey Zigachev  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20*b843c749SSergey Zigachev  * OTHER DEALINGS IN THE SOFTWARE.
21*b843c749SSergey Zigachev  *
22*b843c749SSergey Zigachev  * Authors: AMD
23*b843c749SSergey Zigachev  *
24*b843c749SSergey Zigachev  */
25*b843c749SSergey Zigachev 
26*b843c749SSergey Zigachev #include "dm_services.h"
27*b843c749SSergey Zigachev 
28*b843c749SSergey Zigachev /*
29*b843c749SSergey Zigachev  * Pre-requisites: headers required by header of this unit
30*b843c749SSergey Zigachev  */
31*b843c749SSergey Zigachev #include "include/i2caux_interface.h"
32*b843c749SSergey Zigachev #include "../engine.h"
33*b843c749SSergey Zigachev #include "../aux_engine.h"
34*b843c749SSergey Zigachev 
35*b843c749SSergey Zigachev /*
36*b843c749SSergey Zigachev  * Header of this unit
37*b843c749SSergey Zigachev  */
38*b843c749SSergey Zigachev 
39*b843c749SSergey Zigachev #include "aux_engine_dce110.h"
40*b843c749SSergey Zigachev 
41*b843c749SSergey Zigachev /*
42*b843c749SSergey Zigachev  * Post-requisites: headers required by this unit
43*b843c749SSergey Zigachev  */
44*b843c749SSergey Zigachev #include "dce/dce_11_0_sh_mask.h"
45*b843c749SSergey Zigachev 
46*b843c749SSergey Zigachev #define CTX \
47*b843c749SSergey Zigachev 	aux110->base.base.ctx
48*b843c749SSergey Zigachev #define REG(reg_name)\
49*b843c749SSergey Zigachev 	(aux110->regs->reg_name)
50*b843c749SSergey Zigachev #include "reg_helper.h"
51*b843c749SSergey Zigachev 
52*b843c749SSergey Zigachev /*
53*b843c749SSergey Zigachev  * This unit
54*b843c749SSergey Zigachev  */
55*b843c749SSergey Zigachev 
56*b843c749SSergey Zigachev /*
57*b843c749SSergey Zigachev  * @brief
58*b843c749SSergey Zigachev  * Cast 'struct aux_engine *'
59*b843c749SSergey Zigachev  * to 'struct aux_engine_dce110 *'
60*b843c749SSergey Zigachev  */
61*b843c749SSergey Zigachev #define FROM_AUX_ENGINE(ptr) \
62*b843c749SSergey Zigachev 	container_of((ptr), struct aux_engine_dce110, base)
63*b843c749SSergey Zigachev 
64*b843c749SSergey Zigachev /*
65*b843c749SSergey Zigachev  * @brief
66*b843c749SSergey Zigachev  * Cast 'struct engine *'
67*b843c749SSergey Zigachev  * to 'struct aux_engine_dce110 *'
68*b843c749SSergey Zigachev  */
69*b843c749SSergey Zigachev #define FROM_ENGINE(ptr) \
70*b843c749SSergey Zigachev 	FROM_AUX_ENGINE(container_of((ptr), struct aux_engine, base))
71*b843c749SSergey Zigachev 
release_engine(struct engine * engine)72*b843c749SSergey Zigachev static void release_engine(
73*b843c749SSergey Zigachev 	struct engine *engine)
74*b843c749SSergey Zigachev {
75*b843c749SSergey Zigachev 	struct aux_engine_dce110 *aux110 = FROM_ENGINE(engine);
76*b843c749SSergey Zigachev 
77*b843c749SSergey Zigachev 	REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1);
78*b843c749SSergey Zigachev }
79*b843c749SSergey Zigachev 
80*b843c749SSergey Zigachev static void destruct(
81*b843c749SSergey Zigachev 	struct aux_engine_dce110 *engine);
82*b843c749SSergey Zigachev 
destroy(struct aux_engine ** aux_engine)83*b843c749SSergey Zigachev static void destroy(
84*b843c749SSergey Zigachev 	struct aux_engine **aux_engine)
85*b843c749SSergey Zigachev {
86*b843c749SSergey Zigachev 	struct aux_engine_dce110 *engine = FROM_AUX_ENGINE(*aux_engine);
87*b843c749SSergey Zigachev 
88*b843c749SSergey Zigachev 	destruct(engine);
89*b843c749SSergey Zigachev 
90*b843c749SSergey Zigachev 	kfree(engine);
91*b843c749SSergey Zigachev 
92*b843c749SSergey Zigachev 	*aux_engine = NULL;
93*b843c749SSergey Zigachev }
94*b843c749SSergey Zigachev 
95*b843c749SSergey Zigachev #define SW_CAN_ACCESS_AUX 1
96*b843c749SSergey Zigachev #define DMCU_CAN_ACCESS_AUX 2
97*b843c749SSergey Zigachev 
is_engine_available(struct aux_engine * engine)98*b843c749SSergey Zigachev static bool is_engine_available(
99*b843c749SSergey Zigachev 	struct aux_engine *engine)
100*b843c749SSergey Zigachev {
101*b843c749SSergey Zigachev 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
102*b843c749SSergey Zigachev 
103*b843c749SSergey Zigachev 	uint32_t value = REG_READ(AUX_ARB_CONTROL);
104*b843c749SSergey Zigachev 	uint32_t field = get_reg_field_value(
105*b843c749SSergey Zigachev 			value,
106*b843c749SSergey Zigachev 			AUX_ARB_CONTROL,
107*b843c749SSergey Zigachev 			AUX_REG_RW_CNTL_STATUS);
108*b843c749SSergey Zigachev 
109*b843c749SSergey Zigachev 	return (field != DMCU_CAN_ACCESS_AUX);
110*b843c749SSergey Zigachev }
acquire_engine(struct aux_engine * engine)111*b843c749SSergey Zigachev static bool acquire_engine(
112*b843c749SSergey Zigachev 	struct aux_engine *engine)
113*b843c749SSergey Zigachev {
114*b843c749SSergey Zigachev 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
115*b843c749SSergey Zigachev 
116*b843c749SSergey Zigachev 	uint32_t value = REG_READ(AUX_ARB_CONTROL);
117*b843c749SSergey Zigachev 	uint32_t field = get_reg_field_value(
118*b843c749SSergey Zigachev 			value,
119*b843c749SSergey Zigachev 			AUX_ARB_CONTROL,
120*b843c749SSergey Zigachev 			AUX_REG_RW_CNTL_STATUS);
121*b843c749SSergey Zigachev 	if (field == DMCU_CAN_ACCESS_AUX)
122*b843c749SSergey Zigachev 	 return false;
123*b843c749SSergey Zigachev 	/* enable AUX before request SW to access AUX */
124*b843c749SSergey Zigachev 	value = REG_READ(AUX_CONTROL);
125*b843c749SSergey Zigachev 	field = get_reg_field_value(value,
126*b843c749SSergey Zigachev 				AUX_CONTROL,
127*b843c749SSergey Zigachev 				AUX_EN);
128*b843c749SSergey Zigachev 
129*b843c749SSergey Zigachev 	if (field == 0) {
130*b843c749SSergey Zigachev 		set_reg_field_value(
131*b843c749SSergey Zigachev 				value,
132*b843c749SSergey Zigachev 				1,
133*b843c749SSergey Zigachev 				AUX_CONTROL,
134*b843c749SSergey Zigachev 				AUX_EN);
135*b843c749SSergey Zigachev 
136*b843c749SSergey Zigachev 		if (REG(AUX_RESET_MASK)) {
137*b843c749SSergey Zigachev 			/*DP_AUX block as part of the enable sequence*/
138*b843c749SSergey Zigachev 			set_reg_field_value(
139*b843c749SSergey Zigachev 				value,
140*b843c749SSergey Zigachev 				1,
141*b843c749SSergey Zigachev 				AUX_CONTROL,
142*b843c749SSergey Zigachev 				AUX_RESET);
143*b843c749SSergey Zigachev 		}
144*b843c749SSergey Zigachev 
145*b843c749SSergey Zigachev 		REG_WRITE(AUX_CONTROL, value);
146*b843c749SSergey Zigachev 
147*b843c749SSergey Zigachev 		if (REG(AUX_RESET_MASK)) {
148*b843c749SSergey Zigachev 			/*poll HW to make sure reset it done*/
149*b843c749SSergey Zigachev 
150*b843c749SSergey Zigachev 			REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 1,
151*b843c749SSergey Zigachev 					1, 11);
152*b843c749SSergey Zigachev 
153*b843c749SSergey Zigachev 			set_reg_field_value(
154*b843c749SSergey Zigachev 				value,
155*b843c749SSergey Zigachev 				0,
156*b843c749SSergey Zigachev 				AUX_CONTROL,
157*b843c749SSergey Zigachev 				AUX_RESET);
158*b843c749SSergey Zigachev 
159*b843c749SSergey Zigachev 			REG_WRITE(AUX_CONTROL, value);
160*b843c749SSergey Zigachev 
161*b843c749SSergey Zigachev 			REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 0,
162*b843c749SSergey Zigachev 					1, 11);
163*b843c749SSergey Zigachev 		}
164*b843c749SSergey Zigachev 	} /*if (field)*/
165*b843c749SSergey Zigachev 
166*b843c749SSergey Zigachev 	/* request SW to access AUX */
167*b843c749SSergey Zigachev 	REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_USE_AUX_REG_REQ, 1);
168*b843c749SSergey Zigachev 
169*b843c749SSergey Zigachev 	value = REG_READ(AUX_ARB_CONTROL);
170*b843c749SSergey Zigachev 	field = get_reg_field_value(
171*b843c749SSergey Zigachev 			value,
172*b843c749SSergey Zigachev 			AUX_ARB_CONTROL,
173*b843c749SSergey Zigachev 			AUX_REG_RW_CNTL_STATUS);
174*b843c749SSergey Zigachev 
175*b843c749SSergey Zigachev 	return (field == SW_CAN_ACCESS_AUX);
176*b843c749SSergey Zigachev }
177*b843c749SSergey Zigachev 
178*b843c749SSergey Zigachev #define COMPOSE_AUX_SW_DATA_16_20(command, address) \
179*b843c749SSergey Zigachev 	((command) | ((0xF0000 & (address)) >> 16))
180*b843c749SSergey Zigachev 
181*b843c749SSergey Zigachev #define COMPOSE_AUX_SW_DATA_8_15(address) \
182*b843c749SSergey Zigachev 	((0xFF00 & (address)) >> 8)
183*b843c749SSergey Zigachev 
184*b843c749SSergey Zigachev #define COMPOSE_AUX_SW_DATA_0_7(address) \
185*b843c749SSergey Zigachev 	(0xFF & (address))
186*b843c749SSergey Zigachev 
submit_channel_request(struct aux_engine * engine,struct aux_request_transaction_data * request)187*b843c749SSergey Zigachev static void submit_channel_request(
188*b843c749SSergey Zigachev 	struct aux_engine *engine,
189*b843c749SSergey Zigachev 	struct aux_request_transaction_data *request)
190*b843c749SSergey Zigachev {
191*b843c749SSergey Zigachev 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
192*b843c749SSergey Zigachev 	uint32_t value;
193*b843c749SSergey Zigachev 	uint32_t length;
194*b843c749SSergey Zigachev 
195*b843c749SSergey Zigachev 	bool is_write =
196*b843c749SSergey Zigachev 		((request->type == AUX_TRANSACTION_TYPE_DP) &&
197*b843c749SSergey Zigachev 		 (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) ||
198*b843c749SSergey Zigachev 		((request->type == AUX_TRANSACTION_TYPE_I2C) &&
199*b843c749SSergey Zigachev 		((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
200*b843c749SSergey Zigachev 		 (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT)));
201*b843c749SSergey Zigachev 	if (REG(AUXN_IMPCAL)) {
202*b843c749SSergey Zigachev 		/* clear_aux_error */
203*b843c749SSergey Zigachev 		REG_UPDATE_SEQ(AUXN_IMPCAL, AUXN_CALOUT_ERROR_AK,
204*b843c749SSergey Zigachev 				1,
205*b843c749SSergey Zigachev 				0);
206*b843c749SSergey Zigachev 
207*b843c749SSergey Zigachev 		REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_CALOUT_ERROR_AK,
208*b843c749SSergey Zigachev 				1,
209*b843c749SSergey Zigachev 				0);
210*b843c749SSergey Zigachev 
211*b843c749SSergey Zigachev 		/* force_default_calibrate */
212*b843c749SSergey Zigachev 		REG_UPDATE_1BY1_2(AUXN_IMPCAL,
213*b843c749SSergey Zigachev 				AUXN_IMPCAL_ENABLE, 1,
214*b843c749SSergey Zigachev 				AUXN_IMPCAL_OVERRIDE_ENABLE, 0);
215*b843c749SSergey Zigachev 
216*b843c749SSergey Zigachev 		/* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */
217*b843c749SSergey Zigachev 
218*b843c749SSergey Zigachev 		REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_IMPCAL_OVERRIDE_ENABLE,
219*b843c749SSergey Zigachev 				1,
220*b843c749SSergey Zigachev 				0);
221*b843c749SSergey Zigachev 	}
222*b843c749SSergey Zigachev 	/* set the delay and the number of bytes to write */
223*b843c749SSergey Zigachev 
224*b843c749SSergey Zigachev 	/* The length include
225*b843c749SSergey Zigachev 	 * the 4 bit header and the 20 bit address
226*b843c749SSergey Zigachev 	 * (that is 3 byte).
227*b843c749SSergey Zigachev 	 * If the requested length is non zero this means
228*b843c749SSergey Zigachev 	 * an addition byte specifying the length is required. */
229*b843c749SSergey Zigachev 
230*b843c749SSergey Zigachev 	length = request->length ? 4 : 3;
231*b843c749SSergey Zigachev 	if (is_write)
232*b843c749SSergey Zigachev 		length += request->length;
233*b843c749SSergey Zigachev 
234*b843c749SSergey Zigachev 	REG_UPDATE_2(AUX_SW_CONTROL,
235*b843c749SSergey Zigachev 			AUX_SW_START_DELAY, request->delay,
236*b843c749SSergey Zigachev 			AUX_SW_WR_BYTES, length);
237*b843c749SSergey Zigachev 
238*b843c749SSergey Zigachev 	/* program action and address and payload data (if 'is_write') */
239*b843c749SSergey Zigachev 	value = REG_UPDATE_4(AUX_SW_DATA,
240*b843c749SSergey Zigachev 			AUX_SW_INDEX, 0,
241*b843c749SSergey Zigachev 			AUX_SW_DATA_RW, 0,
242*b843c749SSergey Zigachev 			AUX_SW_AUTOINCREMENT_DISABLE, 1,
243*b843c749SSergey Zigachev 			AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address));
244*b843c749SSergey Zigachev 
245*b843c749SSergey Zigachev 	value = REG_SET_2(AUX_SW_DATA, value,
246*b843c749SSergey Zigachev 			AUX_SW_AUTOINCREMENT_DISABLE, 0,
247*b843c749SSergey Zigachev 			AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address));
248*b843c749SSergey Zigachev 
249*b843c749SSergey Zigachev 	value = REG_SET(AUX_SW_DATA, value,
250*b843c749SSergey Zigachev 			AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address));
251*b843c749SSergey Zigachev 
252*b843c749SSergey Zigachev 	if (request->length) {
253*b843c749SSergey Zigachev 		value = REG_SET(AUX_SW_DATA, value,
254*b843c749SSergey Zigachev 				AUX_SW_DATA, request->length - 1);
255*b843c749SSergey Zigachev 	}
256*b843c749SSergey Zigachev 
257*b843c749SSergey Zigachev 	if (is_write) {
258*b843c749SSergey Zigachev 		/* Load the HW buffer with the Data to be sent.
259*b843c749SSergey Zigachev 		 * This is relevant for write operation.
260*b843c749SSergey Zigachev 		 * For read, the data recived data will be
261*b843c749SSergey Zigachev 		 * processed in process_channel_reply(). */
262*b843c749SSergey Zigachev 		uint32_t i = 0;
263*b843c749SSergey Zigachev 
264*b843c749SSergey Zigachev 		while (i < request->length) {
265*b843c749SSergey Zigachev 			value = REG_SET(AUX_SW_DATA, value,
266*b843c749SSergey Zigachev 					AUX_SW_DATA, request->data[i]);
267*b843c749SSergey Zigachev 
268*b843c749SSergey Zigachev 			++i;
269*b843c749SSergey Zigachev 		}
270*b843c749SSergey Zigachev 	}
271*b843c749SSergey Zigachev 
272*b843c749SSergey Zigachev 	REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1);
273*b843c749SSergey Zigachev 	REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0,
274*b843c749SSergey Zigachev 				10, aux110->timeout_period/10);
275*b843c749SSergey Zigachev 	REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
276*b843c749SSergey Zigachev }
277*b843c749SSergey Zigachev 
read_channel_reply(struct aux_engine * engine,uint32_t size,uint8_t * buffer,uint8_t * reply_result,uint32_t * sw_status)278*b843c749SSergey Zigachev static int read_channel_reply(struct aux_engine *engine, uint32_t size,
279*b843c749SSergey Zigachev 			      uint8_t *buffer, uint8_t *reply_result,
280*b843c749SSergey Zigachev 			      uint32_t *sw_status)
281*b843c749SSergey Zigachev {
282*b843c749SSergey Zigachev 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
283*b843c749SSergey Zigachev 	uint32_t bytes_replied;
284*b843c749SSergey Zigachev 	uint32_t reply_result_32;
285*b843c749SSergey Zigachev 
286*b843c749SSergey Zigachev 	*sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT,
287*b843c749SSergey Zigachev 			     &bytes_replied);
288*b843c749SSergey Zigachev 
289*b843c749SSergey Zigachev 	/* In case HPD is LOW, exit AUX transaction */
290*b843c749SSergey Zigachev 	if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
291*b843c749SSergey Zigachev 		return -1;
292*b843c749SSergey Zigachev 
293*b843c749SSergey Zigachev 	/* Need at least the status byte */
294*b843c749SSergey Zigachev 	if (!bytes_replied)
295*b843c749SSergey Zigachev 		return -1;
296*b843c749SSergey Zigachev 
297*b843c749SSergey Zigachev 	REG_UPDATE_1BY1_3(AUX_SW_DATA,
298*b843c749SSergey Zigachev 			  AUX_SW_INDEX, 0,
299*b843c749SSergey Zigachev 			  AUX_SW_AUTOINCREMENT_DISABLE, 1,
300*b843c749SSergey Zigachev 			  AUX_SW_DATA_RW, 1);
301*b843c749SSergey Zigachev 
302*b843c749SSergey Zigachev 	REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32);
303*b843c749SSergey Zigachev 	reply_result_32 = reply_result_32 >> 4;
304*b843c749SSergey Zigachev 	*reply_result = (uint8_t)reply_result_32;
305*b843c749SSergey Zigachev 
306*b843c749SSergey Zigachev 	if (reply_result_32 == 0) { /* ACK */
307*b843c749SSergey Zigachev 		uint32_t i = 0;
308*b843c749SSergey Zigachev 
309*b843c749SSergey Zigachev 		/* First byte was already used to get the command status */
310*b843c749SSergey Zigachev 		--bytes_replied;
311*b843c749SSergey Zigachev 
312*b843c749SSergey Zigachev 		/* Do not overflow buffer */
313*b843c749SSergey Zigachev 		if (bytes_replied > size)
314*b843c749SSergey Zigachev 			return -1;
315*b843c749SSergey Zigachev 
316*b843c749SSergey Zigachev 		while (i < bytes_replied) {
317*b843c749SSergey Zigachev 			uint32_t aux_sw_data_val;
318*b843c749SSergey Zigachev 
319*b843c749SSergey Zigachev 			REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val);
320*b843c749SSergey Zigachev 			buffer[i] = aux_sw_data_val;
321*b843c749SSergey Zigachev 			++i;
322*b843c749SSergey Zigachev 		}
323*b843c749SSergey Zigachev 
324*b843c749SSergey Zigachev 		return i;
325*b843c749SSergey Zigachev 	}
326*b843c749SSergey Zigachev 
327*b843c749SSergey Zigachev 	return 0;
328*b843c749SSergey Zigachev }
329*b843c749SSergey Zigachev 
process_channel_reply(struct aux_engine * engine,struct aux_reply_transaction_data * reply)330*b843c749SSergey Zigachev static void process_channel_reply(
331*b843c749SSergey Zigachev 	struct aux_engine *engine,
332*b843c749SSergey Zigachev 	struct aux_reply_transaction_data *reply)
333*b843c749SSergey Zigachev {
334*b843c749SSergey Zigachev 	int bytes_replied;
335*b843c749SSergey Zigachev 	uint8_t reply_result;
336*b843c749SSergey Zigachev 	uint32_t sw_status;
337*b843c749SSergey Zigachev 
338*b843c749SSergey Zigachev 	bytes_replied = read_channel_reply(engine, reply->length, reply->data,
339*b843c749SSergey Zigachev 					   &reply_result, &sw_status);
340*b843c749SSergey Zigachev 
341*b843c749SSergey Zigachev 	/* in case HPD is LOW, exit AUX transaction */
342*b843c749SSergey Zigachev 	if ((sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
343*b843c749SSergey Zigachev 		reply->status = AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
344*b843c749SSergey Zigachev 		return;
345*b843c749SSergey Zigachev 	}
346*b843c749SSergey Zigachev 
347*b843c749SSergey Zigachev 	if (bytes_replied < 0) {
348*b843c749SSergey Zigachev 		/* Need to handle an error case...
349*b843c749SSergey Zigachev 		 * Hopefully, upper layer function won't call this function if
350*b843c749SSergey Zigachev 		 * the number of bytes in the reply was 0, because there was
351*b843c749SSergey Zigachev 		 * surely an error that was asserted that should have been
352*b843c749SSergey Zigachev 		 * handled for hot plug case, this could happens
353*b843c749SSergey Zigachev 		 */
354*b843c749SSergey Zigachev 		if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
355*b843c749SSergey Zigachev 			reply->status = AUX_TRANSACTION_REPLY_INVALID;
356*b843c749SSergey Zigachev 			ASSERT_CRITICAL(false);
357*b843c749SSergey Zigachev 			return;
358*b843c749SSergey Zigachev 		}
359*b843c749SSergey Zigachev 	} else {
360*b843c749SSergey Zigachev 
361*b843c749SSergey Zigachev 		switch (reply_result) {
362*b843c749SSergey Zigachev 		case 0: /* ACK */
363*b843c749SSergey Zigachev 			reply->status = AUX_TRANSACTION_REPLY_AUX_ACK;
364*b843c749SSergey Zigachev 		break;
365*b843c749SSergey Zigachev 		case 1: /* NACK */
366*b843c749SSergey Zigachev 			reply->status = AUX_TRANSACTION_REPLY_AUX_NACK;
367*b843c749SSergey Zigachev 		break;
368*b843c749SSergey Zigachev 		case 2: /* DEFER */
369*b843c749SSergey Zigachev 			reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER;
370*b843c749SSergey Zigachev 		break;
371*b843c749SSergey Zigachev 		case 4: /* AUX ACK / I2C NACK */
372*b843c749SSergey Zigachev 			reply->status = AUX_TRANSACTION_REPLY_I2C_NACK;
373*b843c749SSergey Zigachev 		break;
374*b843c749SSergey Zigachev 		case 8: /* AUX ACK / I2C DEFER */
375*b843c749SSergey Zigachev 			reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER;
376*b843c749SSergey Zigachev 		break;
377*b843c749SSergey Zigachev 		default:
378*b843c749SSergey Zigachev 			reply->status = AUX_TRANSACTION_REPLY_INVALID;
379*b843c749SSergey Zigachev 		}
380*b843c749SSergey Zigachev 	}
381*b843c749SSergey Zigachev }
382*b843c749SSergey Zigachev 
get_channel_status(struct aux_engine * engine,uint8_t * returned_bytes)383*b843c749SSergey Zigachev static enum aux_channel_operation_result get_channel_status(
384*b843c749SSergey Zigachev 	struct aux_engine *engine,
385*b843c749SSergey Zigachev 	uint8_t *returned_bytes)
386*b843c749SSergey Zigachev {
387*b843c749SSergey Zigachev 	struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
388*b843c749SSergey Zigachev 
389*b843c749SSergey Zigachev 	uint32_t value;
390*b843c749SSergey Zigachev 
391*b843c749SSergey Zigachev 	if (returned_bytes == NULL) {
392*b843c749SSergey Zigachev 		/*caller pass NULL pointer*/
393*b843c749SSergey Zigachev 		ASSERT_CRITICAL(false);
394*b843c749SSergey Zigachev 		return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN;
395*b843c749SSergey Zigachev 	}
396*b843c749SSergey Zigachev 	*returned_bytes = 0;
397*b843c749SSergey Zigachev 
398*b843c749SSergey Zigachev 	/* poll to make sure that SW_DONE is asserted */
399*b843c749SSergey Zigachev 	value = REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1,
400*b843c749SSergey Zigachev 				10, aux110->timeout_period/10);
401*b843c749SSergey Zigachev 
402*b843c749SSergey Zigachev 	/* in case HPD is LOW, exit AUX transaction */
403*b843c749SSergey Zigachev 	if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
404*b843c749SSergey Zigachev 		return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON;
405*b843c749SSergey Zigachev 
406*b843c749SSergey Zigachev 	/* Note that the following bits are set in 'status.bits'
407*b843c749SSergey Zigachev 	 * during CTS 4.2.1.2 (FW 3.3.1):
408*b843c749SSergey Zigachev 	 * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP,
409*b843c749SSergey Zigachev 	 * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H.
410*b843c749SSergey Zigachev 	 *
411*b843c749SSergey Zigachev 	 * AUX_SW_RX_MIN_COUNT_VIOL is an internal,
412*b843c749SSergey Zigachev 	 * HW debugging bit and should be ignored. */
413*b843c749SSergey Zigachev 	if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) {
414*b843c749SSergey Zigachev 		if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) ||
415*b843c749SSergey Zigachev 			(value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK))
416*b843c749SSergey Zigachev 			return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
417*b843c749SSergey Zigachev 
418*b843c749SSergey Zigachev 		else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) ||
419*b843c749SSergey Zigachev 			(value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) ||
420*b843c749SSergey Zigachev 			(value &
421*b843c749SSergey Zigachev 				AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) ||
422*b843c749SSergey Zigachev 			(value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK))
423*b843c749SSergey Zigachev 			return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
424*b843c749SSergey Zigachev 
425*b843c749SSergey Zigachev 		*returned_bytes = get_reg_field_value(value,
426*b843c749SSergey Zigachev 				AUX_SW_STATUS,
427*b843c749SSergey Zigachev 				AUX_SW_REPLY_BYTE_COUNT);
428*b843c749SSergey Zigachev 
429*b843c749SSergey Zigachev 		if (*returned_bytes == 0)
430*b843c749SSergey Zigachev 			return
431*b843c749SSergey Zigachev 			AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
432*b843c749SSergey Zigachev 		else {
433*b843c749SSergey Zigachev 			*returned_bytes -= 1;
434*b843c749SSergey Zigachev 			return AUX_CHANNEL_OPERATION_SUCCEEDED;
435*b843c749SSergey Zigachev 		}
436*b843c749SSergey Zigachev 	} else {
437*b843c749SSergey Zigachev 		/*time_elapsed >= aux_engine->timeout_period
438*b843c749SSergey Zigachev 		 *  AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point
439*b843c749SSergey Zigachev 		 */
440*b843c749SSergey Zigachev 		ASSERT_CRITICAL(false);
441*b843c749SSergey Zigachev 		return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
442*b843c749SSergey Zigachev 	}
443*b843c749SSergey Zigachev }
444*b843c749SSergey Zigachev 
445*b843c749SSergey Zigachev static const struct aux_engine_funcs aux_engine_funcs = {
446*b843c749SSergey Zigachev 	.destroy = destroy,
447*b843c749SSergey Zigachev 	.acquire_engine = acquire_engine,
448*b843c749SSergey Zigachev 	.submit_channel_request = submit_channel_request,
449*b843c749SSergey Zigachev 	.process_channel_reply = process_channel_reply,
450*b843c749SSergey Zigachev 	.read_channel_reply = read_channel_reply,
451*b843c749SSergey Zigachev 	.get_channel_status = get_channel_status,
452*b843c749SSergey Zigachev 	.is_engine_available = is_engine_available,
453*b843c749SSergey Zigachev };
454*b843c749SSergey Zigachev 
455*b843c749SSergey Zigachev static const struct engine_funcs engine_funcs = {
456*b843c749SSergey Zigachev 	.release_engine = release_engine,
457*b843c749SSergey Zigachev 	.submit_request = dal_aux_engine_submit_request,
458*b843c749SSergey Zigachev 	.get_engine_type = dal_aux_engine_get_engine_type,
459*b843c749SSergey Zigachev 	.acquire = dal_aux_engine_acquire,
460*b843c749SSergey Zigachev };
461*b843c749SSergey Zigachev 
construct(struct aux_engine_dce110 * engine,const struct aux_engine_dce110_init_data * aux_init_data)462*b843c749SSergey Zigachev static void construct(
463*b843c749SSergey Zigachev 	struct aux_engine_dce110 *engine,
464*b843c749SSergey Zigachev 	const struct aux_engine_dce110_init_data *aux_init_data)
465*b843c749SSergey Zigachev {
466*b843c749SSergey Zigachev 	dal_aux_engine_construct(&engine->base, aux_init_data->ctx);
467*b843c749SSergey Zigachev 	engine->base.base.funcs = &engine_funcs;
468*b843c749SSergey Zigachev 	engine->base.funcs = &aux_engine_funcs;
469*b843c749SSergey Zigachev 
470*b843c749SSergey Zigachev 	engine->timeout_period = aux_init_data->timeout_period;
471*b843c749SSergey Zigachev 	engine->regs = aux_init_data->regs;
472*b843c749SSergey Zigachev }
473*b843c749SSergey Zigachev 
destruct(struct aux_engine_dce110 * engine)474*b843c749SSergey Zigachev static void destruct(
475*b843c749SSergey Zigachev 	struct aux_engine_dce110 *engine)
476*b843c749SSergey Zigachev {
477*b843c749SSergey Zigachev 	dal_aux_engine_destruct(&engine->base);
478*b843c749SSergey Zigachev }
479*b843c749SSergey Zigachev 
dal_aux_engine_dce110_create(const struct aux_engine_dce110_init_data * aux_init_data)480*b843c749SSergey Zigachev struct aux_engine *dal_aux_engine_dce110_create(
481*b843c749SSergey Zigachev 	const struct aux_engine_dce110_init_data *aux_init_data)
482*b843c749SSergey Zigachev {
483*b843c749SSergey Zigachev 	struct aux_engine_dce110 *engine;
484*b843c749SSergey Zigachev 
485*b843c749SSergey Zigachev 	if (!aux_init_data) {
486*b843c749SSergey Zigachev 		ASSERT_CRITICAL(false);
487*b843c749SSergey Zigachev 		return NULL;
488*b843c749SSergey Zigachev 	}
489*b843c749SSergey Zigachev 
490*b843c749SSergey Zigachev 	engine = kzalloc(sizeof(*engine), GFP_KERNEL);
491*b843c749SSergey Zigachev 
492*b843c749SSergey Zigachev 	if (!engine) {
493*b843c749SSergey Zigachev 		ASSERT_CRITICAL(false);
494*b843c749SSergey Zigachev 		return NULL;
495*b843c749SSergey Zigachev 	}
496*b843c749SSergey Zigachev 
497*b843c749SSergey Zigachev 	construct(engine, aux_init_data);
498*b843c749SSergey Zigachev 	return &engine->base;
499*b843c749SSergey Zigachev }
500