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 "i2c_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 "i2c_hw_engine.h"
40*b843c749SSergey Zigachev
41*b843c749SSergey Zigachev /*
42*b843c749SSergey Zigachev * Post-requisites: headers required by this unit
43*b843c749SSergey Zigachev */
44*b843c749SSergey Zigachev
45*b843c749SSergey Zigachev /*
46*b843c749SSergey Zigachev * This unit
47*b843c749SSergey Zigachev */
48*b843c749SSergey Zigachev
49*b843c749SSergey Zigachev /*
50*b843c749SSergey Zigachev * @brief
51*b843c749SSergey Zigachev * Cast 'struct i2c_engine *'
52*b843c749SSergey Zigachev * to 'struct i2c_hw_engine *'
53*b843c749SSergey Zigachev */
54*b843c749SSergey Zigachev #define FROM_I2C_ENGINE(ptr) \
55*b843c749SSergey Zigachev container_of((ptr), struct i2c_hw_engine, base)
56*b843c749SSergey Zigachev
57*b843c749SSergey Zigachev /*
58*b843c749SSergey Zigachev * @brief
59*b843c749SSergey Zigachev * Cast 'struct engine *'
60*b843c749SSergey Zigachev * to 'struct i2c_hw_engine *'
61*b843c749SSergey Zigachev */
62*b843c749SSergey Zigachev #define FROM_ENGINE(ptr) \
63*b843c749SSergey Zigachev FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base))
64*b843c749SSergey Zigachev
dal_i2c_hw_engine_get_engine_type(const struct engine * engine)65*b843c749SSergey Zigachev enum i2caux_engine_type dal_i2c_hw_engine_get_engine_type(
66*b843c749SSergey Zigachev const struct engine *engine)
67*b843c749SSergey Zigachev {
68*b843c749SSergey Zigachev return I2CAUX_ENGINE_TYPE_I2C_DDC_HW;
69*b843c749SSergey Zigachev }
70*b843c749SSergey Zigachev
dal_i2c_hw_engine_submit_request(struct engine * engine,struct i2caux_transaction_request * i2caux_request,bool middle_of_transaction)71*b843c749SSergey Zigachev bool dal_i2c_hw_engine_submit_request(
72*b843c749SSergey Zigachev struct engine *engine,
73*b843c749SSergey Zigachev struct i2caux_transaction_request *i2caux_request,
74*b843c749SSergey Zigachev bool middle_of_transaction)
75*b843c749SSergey Zigachev {
76*b843c749SSergey Zigachev struct i2c_hw_engine *hw_engine = FROM_ENGINE(engine);
77*b843c749SSergey Zigachev
78*b843c749SSergey Zigachev struct i2c_request_transaction_data request;
79*b843c749SSergey Zigachev
80*b843c749SSergey Zigachev uint32_t transaction_timeout;
81*b843c749SSergey Zigachev
82*b843c749SSergey Zigachev enum i2c_channel_operation_result operation_result;
83*b843c749SSergey Zigachev
84*b843c749SSergey Zigachev bool result = false;
85*b843c749SSergey Zigachev
86*b843c749SSergey Zigachev /* We need following:
87*b843c749SSergey Zigachev * transaction length will not exceed
88*b843c749SSergey Zigachev * the number of free bytes in HW buffer (minus one for address)*/
89*b843c749SSergey Zigachev
90*b843c749SSergey Zigachev if (i2caux_request->payload.length >=
91*b843c749SSergey Zigachev hw_engine->funcs->get_hw_buffer_available_size(hw_engine)) {
92*b843c749SSergey Zigachev i2caux_request->status =
93*b843c749SSergey Zigachev I2CAUX_TRANSACTION_STATUS_FAILED_BUFFER_OVERFLOW;
94*b843c749SSergey Zigachev return false;
95*b843c749SSergey Zigachev }
96*b843c749SSergey Zigachev
97*b843c749SSergey Zigachev if (i2caux_request->operation == I2CAUX_TRANSACTION_READ)
98*b843c749SSergey Zigachev request.action = middle_of_transaction ?
99*b843c749SSergey Zigachev I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
100*b843c749SSergey Zigachev I2CAUX_TRANSACTION_ACTION_I2C_READ;
101*b843c749SSergey Zigachev else if (i2caux_request->operation == I2CAUX_TRANSACTION_WRITE)
102*b843c749SSergey Zigachev request.action = middle_of_transaction ?
103*b843c749SSergey Zigachev I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
104*b843c749SSergey Zigachev I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
105*b843c749SSergey Zigachev else {
106*b843c749SSergey Zigachev i2caux_request->status =
107*b843c749SSergey Zigachev I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION;
108*b843c749SSergey Zigachev /* [anaumov] in DAL2, there was no "return false" */
109*b843c749SSergey Zigachev return false;
110*b843c749SSergey Zigachev }
111*b843c749SSergey Zigachev
112*b843c749SSergey Zigachev request.address = (uint8_t)i2caux_request->payload.address;
113*b843c749SSergey Zigachev request.length = i2caux_request->payload.length;
114*b843c749SSergey Zigachev request.data = i2caux_request->payload.data;
115*b843c749SSergey Zigachev
116*b843c749SSergey Zigachev /* obtain timeout value before submitting request */
117*b843c749SSergey Zigachev
118*b843c749SSergey Zigachev transaction_timeout = hw_engine->funcs->get_transaction_timeout(
119*b843c749SSergey Zigachev hw_engine, i2caux_request->payload.length + 1);
120*b843c749SSergey Zigachev
121*b843c749SSergey Zigachev hw_engine->base.funcs->submit_channel_request(
122*b843c749SSergey Zigachev &hw_engine->base, &request);
123*b843c749SSergey Zigachev
124*b843c749SSergey Zigachev if ((request.status == I2C_CHANNEL_OPERATION_FAILED) ||
125*b843c749SSergey Zigachev (request.status == I2C_CHANNEL_OPERATION_ENGINE_BUSY)) {
126*b843c749SSergey Zigachev i2caux_request->status =
127*b843c749SSergey Zigachev I2CAUX_TRANSACTION_STATUS_FAILED_CHANNEL_BUSY;
128*b843c749SSergey Zigachev return false;
129*b843c749SSergey Zigachev }
130*b843c749SSergey Zigachev
131*b843c749SSergey Zigachev /* wait until transaction proceed */
132*b843c749SSergey Zigachev
133*b843c749SSergey Zigachev operation_result = hw_engine->funcs->wait_on_operation_result(
134*b843c749SSergey Zigachev hw_engine,
135*b843c749SSergey Zigachev transaction_timeout,
136*b843c749SSergey Zigachev I2C_CHANNEL_OPERATION_ENGINE_BUSY);
137*b843c749SSergey Zigachev
138*b843c749SSergey Zigachev /* update transaction status */
139*b843c749SSergey Zigachev
140*b843c749SSergey Zigachev switch (operation_result) {
141*b843c749SSergey Zigachev case I2C_CHANNEL_OPERATION_SUCCEEDED:
142*b843c749SSergey Zigachev i2caux_request->status =
143*b843c749SSergey Zigachev I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
144*b843c749SSergey Zigachev result = true;
145*b843c749SSergey Zigachev break;
146*b843c749SSergey Zigachev case I2C_CHANNEL_OPERATION_NO_RESPONSE:
147*b843c749SSergey Zigachev i2caux_request->status =
148*b843c749SSergey Zigachev I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
149*b843c749SSergey Zigachev break;
150*b843c749SSergey Zigachev case I2C_CHANNEL_OPERATION_TIMEOUT:
151*b843c749SSergey Zigachev i2caux_request->status =
152*b843c749SSergey Zigachev I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
153*b843c749SSergey Zigachev break;
154*b843c749SSergey Zigachev case I2C_CHANNEL_OPERATION_FAILED:
155*b843c749SSergey Zigachev i2caux_request->status =
156*b843c749SSergey Zigachev I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE;
157*b843c749SSergey Zigachev break;
158*b843c749SSergey Zigachev default:
159*b843c749SSergey Zigachev i2caux_request->status =
160*b843c749SSergey Zigachev I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION;
161*b843c749SSergey Zigachev }
162*b843c749SSergey Zigachev
163*b843c749SSergey Zigachev if (result && (i2caux_request->operation == I2CAUX_TRANSACTION_READ)) {
164*b843c749SSergey Zigachev struct i2c_reply_transaction_data reply;
165*b843c749SSergey Zigachev
166*b843c749SSergey Zigachev reply.data = i2caux_request->payload.data;
167*b843c749SSergey Zigachev reply.length = i2caux_request->payload.length;
168*b843c749SSergey Zigachev
169*b843c749SSergey Zigachev hw_engine->base.funcs->
170*b843c749SSergey Zigachev process_channel_reply(&hw_engine->base, &reply);
171*b843c749SSergey Zigachev }
172*b843c749SSergey Zigachev
173*b843c749SSergey Zigachev return result;
174*b843c749SSergey Zigachev }
175*b843c749SSergey Zigachev
dal_i2c_hw_engine_acquire_engine(struct i2c_engine * engine,struct ddc * ddc)176*b843c749SSergey Zigachev bool dal_i2c_hw_engine_acquire_engine(
177*b843c749SSergey Zigachev struct i2c_engine *engine,
178*b843c749SSergey Zigachev struct ddc *ddc)
179*b843c749SSergey Zigachev {
180*b843c749SSergey Zigachev enum gpio_result result;
181*b843c749SSergey Zigachev uint32_t current_speed;
182*b843c749SSergey Zigachev
183*b843c749SSergey Zigachev result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
184*b843c749SSergey Zigachev GPIO_DDC_CONFIG_TYPE_MODE_I2C);
185*b843c749SSergey Zigachev
186*b843c749SSergey Zigachev if (result != GPIO_RESULT_OK)
187*b843c749SSergey Zigachev return false;
188*b843c749SSergey Zigachev
189*b843c749SSergey Zigachev engine->base.ddc = ddc;
190*b843c749SSergey Zigachev
191*b843c749SSergey Zigachev current_speed = engine->funcs->get_speed(engine);
192*b843c749SSergey Zigachev
193*b843c749SSergey Zigachev if (current_speed)
194*b843c749SSergey Zigachev FROM_I2C_ENGINE(engine)->original_speed = current_speed;
195*b843c749SSergey Zigachev
196*b843c749SSergey Zigachev return true;
197*b843c749SSergey Zigachev }
198*b843c749SSergey Zigachev /*
199*b843c749SSergey Zigachev * @brief
200*b843c749SSergey Zigachev * Queries in a loop for current engine status
201*b843c749SSergey Zigachev * until retrieved status matches 'expected_result', or timeout occurs.
202*b843c749SSergey Zigachev * Timeout given in microseconds
203*b843c749SSergey Zigachev * and the status query frequency is also one per microsecond.
204*b843c749SSergey Zigachev */
dal_i2c_hw_engine_wait_on_operation_result(struct i2c_hw_engine * engine,uint32_t timeout,enum i2c_channel_operation_result expected_result)205*b843c749SSergey Zigachev enum i2c_channel_operation_result dal_i2c_hw_engine_wait_on_operation_result(
206*b843c749SSergey Zigachev struct i2c_hw_engine *engine,
207*b843c749SSergey Zigachev uint32_t timeout,
208*b843c749SSergey Zigachev enum i2c_channel_operation_result expected_result)
209*b843c749SSergey Zigachev {
210*b843c749SSergey Zigachev enum i2c_channel_operation_result result;
211*b843c749SSergey Zigachev uint32_t i = 0;
212*b843c749SSergey Zigachev
213*b843c749SSergey Zigachev if (!timeout)
214*b843c749SSergey Zigachev return I2C_CHANNEL_OPERATION_SUCCEEDED;
215*b843c749SSergey Zigachev
216*b843c749SSergey Zigachev do {
217*b843c749SSergey Zigachev result = engine->base.funcs->get_channel_status(
218*b843c749SSergey Zigachev &engine->base, NULL);
219*b843c749SSergey Zigachev
220*b843c749SSergey Zigachev if (result != expected_result)
221*b843c749SSergey Zigachev break;
222*b843c749SSergey Zigachev
223*b843c749SSergey Zigachev udelay(1);
224*b843c749SSergey Zigachev
225*b843c749SSergey Zigachev ++i;
226*b843c749SSergey Zigachev } while (i < timeout);
227*b843c749SSergey Zigachev
228*b843c749SSergey Zigachev return result;
229*b843c749SSergey Zigachev }
230*b843c749SSergey Zigachev
dal_i2c_hw_engine_construct(struct i2c_hw_engine * engine,struct dc_context * ctx)231*b843c749SSergey Zigachev void dal_i2c_hw_engine_construct(
232*b843c749SSergey Zigachev struct i2c_hw_engine *engine,
233*b843c749SSergey Zigachev struct dc_context *ctx)
234*b843c749SSergey Zigachev {
235*b843c749SSergey Zigachev dal_i2c_engine_construct(&engine->base, ctx);
236*b843c749SSergey Zigachev engine->original_speed = I2CAUX_DEFAULT_I2C_HW_SPEED;
237*b843c749SSergey Zigachev engine->default_speed = I2CAUX_DEFAULT_I2C_HW_SPEED;
238*b843c749SSergey Zigachev }
239*b843c749SSergey Zigachev
dal_i2c_hw_engine_destruct(struct i2c_hw_engine * engine)240*b843c749SSergey Zigachev void dal_i2c_hw_engine_destruct(
241*b843c749SSergey Zigachev struct i2c_hw_engine *engine)
242*b843c749SSergey Zigachev {
243*b843c749SSergey Zigachev dal_i2c_engine_destruct(&engine->base);
244*b843c749SSergey Zigachev }
245