Loading...
Note: File does not exist in v6.9.4.
1/*
2 * Copyright 2012-15 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: AMD
23 *
24 */
25
26#include "dm_services.h"
27
28/*
29 * Pre-requisites: headers required by header of this unit
30 */
31#include "include/i2caux_interface.h"
32#include "engine.h"
33#include "i2c_engine.h"
34
35/*
36 * Header of this unit
37 */
38
39#include "i2c_hw_engine.h"
40
41/*
42 * Post-requisites: headers required by this unit
43 */
44
45/*
46 * This unit
47 */
48
49/*
50 * @brief
51 * Cast 'struct i2c_engine *'
52 * to 'struct i2c_hw_engine *'
53 */
54#define FROM_I2C_ENGINE(ptr) \
55 container_of((ptr), struct i2c_hw_engine, base)
56
57/*
58 * @brief
59 * Cast 'struct engine *'
60 * to 'struct i2c_hw_engine *'
61 */
62#define FROM_ENGINE(ptr) \
63 FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base))
64
65enum i2caux_engine_type dal_i2c_hw_engine_get_engine_type(
66 const struct engine *engine)
67{
68 return I2CAUX_ENGINE_TYPE_I2C_DDC_HW;
69}
70
71bool dal_i2c_hw_engine_submit_request(
72 struct engine *engine,
73 struct i2caux_transaction_request *i2caux_request,
74 bool middle_of_transaction)
75{
76 struct i2c_hw_engine *hw_engine = FROM_ENGINE(engine);
77
78 struct i2c_request_transaction_data request;
79
80 uint32_t transaction_timeout;
81
82 enum i2c_channel_operation_result operation_result;
83
84 bool result = false;
85
86 /* We need following:
87 * transaction length will not exceed
88 * the number of free bytes in HW buffer (minus one for address)*/
89
90 if (i2caux_request->payload.length >=
91 hw_engine->funcs->get_hw_buffer_available_size(hw_engine)) {
92 i2caux_request->status =
93 I2CAUX_TRANSACTION_STATUS_FAILED_BUFFER_OVERFLOW;
94 return false;
95 }
96
97 if (i2caux_request->operation == I2CAUX_TRANSACTION_READ)
98 request.action = middle_of_transaction ?
99 I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
100 I2CAUX_TRANSACTION_ACTION_I2C_READ;
101 else if (i2caux_request->operation == I2CAUX_TRANSACTION_WRITE)
102 request.action = middle_of_transaction ?
103 I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
104 I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
105 else {
106 i2caux_request->status =
107 I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION;
108 /* [anaumov] in DAL2, there was no "return false" */
109 return false;
110 }
111
112 request.address = (uint8_t)i2caux_request->payload.address;
113 request.length = i2caux_request->payload.length;
114 request.data = i2caux_request->payload.data;
115
116 /* obtain timeout value before submitting request */
117
118 transaction_timeout = hw_engine->funcs->get_transaction_timeout(
119 hw_engine, i2caux_request->payload.length + 1);
120
121 hw_engine->base.funcs->submit_channel_request(
122 &hw_engine->base, &request);
123
124 if ((request.status == I2C_CHANNEL_OPERATION_FAILED) ||
125 (request.status == I2C_CHANNEL_OPERATION_ENGINE_BUSY)) {
126 i2caux_request->status =
127 I2CAUX_TRANSACTION_STATUS_FAILED_CHANNEL_BUSY;
128 return false;
129 }
130
131 /* wait until transaction proceed */
132
133 operation_result = hw_engine->funcs->wait_on_operation_result(
134 hw_engine,
135 transaction_timeout,
136 I2C_CHANNEL_OPERATION_ENGINE_BUSY);
137
138 /* update transaction status */
139
140 switch (operation_result) {
141 case I2C_CHANNEL_OPERATION_SUCCEEDED:
142 i2caux_request->status =
143 I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
144 result = true;
145 break;
146 case I2C_CHANNEL_OPERATION_NO_RESPONSE:
147 i2caux_request->status =
148 I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
149 break;
150 case I2C_CHANNEL_OPERATION_TIMEOUT:
151 i2caux_request->status =
152 I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
153 break;
154 case I2C_CHANNEL_OPERATION_FAILED:
155 i2caux_request->status =
156 I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE;
157 break;
158 default:
159 i2caux_request->status =
160 I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION;
161 }
162
163 if (result && (i2caux_request->operation == I2CAUX_TRANSACTION_READ)) {
164 struct i2c_reply_transaction_data reply;
165
166 reply.data = i2caux_request->payload.data;
167 reply.length = i2caux_request->payload.length;
168
169 hw_engine->base.funcs->
170 process_channel_reply(&hw_engine->base, &reply);
171 }
172
173 return result;
174}
175
176bool dal_i2c_hw_engine_acquire_engine(
177 struct i2c_engine *engine,
178 struct ddc *ddc)
179{
180 enum gpio_result result;
181 uint32_t current_speed;
182
183 result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
184 GPIO_DDC_CONFIG_TYPE_MODE_I2C);
185
186 if (result != GPIO_RESULT_OK)
187 return false;
188
189 engine->base.ddc = ddc;
190
191 current_speed = engine->funcs->get_speed(engine);
192
193 if (current_speed)
194 FROM_I2C_ENGINE(engine)->original_speed = current_speed;
195
196 return true;
197}
198/*
199 * @brief
200 * Queries in a loop for current engine status
201 * until retrieved status matches 'expected_result', or timeout occurs.
202 * Timeout given in microseconds
203 * and the status query frequency is also one per microsecond.
204 */
205enum i2c_channel_operation_result dal_i2c_hw_engine_wait_on_operation_result(
206 struct i2c_hw_engine *engine,
207 uint32_t timeout,
208 enum i2c_channel_operation_result expected_result)
209{
210 enum i2c_channel_operation_result result;
211 uint32_t i = 0;
212
213 if (!timeout)
214 return I2C_CHANNEL_OPERATION_SUCCEEDED;
215
216 do {
217 result = engine->base.funcs->get_channel_status(
218 &engine->base, NULL);
219
220 if (result != expected_result)
221 break;
222
223 udelay(1);
224
225 ++i;
226 } while (i < timeout);
227
228 return result;
229}
230
231void dal_i2c_hw_engine_construct(
232 struct i2c_hw_engine *engine,
233 struct dc_context *ctx)
234{
235 dal_i2c_engine_construct(&engine->base, ctx);
236 engine->original_speed = I2CAUX_DEFAULT_I2C_HW_SPEED;
237 engine->default_speed = I2CAUX_DEFAULT_I2C_HW_SPEED;
238}
239
240void dal_i2c_hw_engine_destruct(
241 struct i2c_hw_engine *engine)
242{
243 dal_i2c_engine_destruct(&engine->base);
244}