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