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