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 65 enum 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 71 bool 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 176 bool 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 */ 205 enum 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 231 void 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 240 void dal_i2c_hw_engine_destruct( 241 struct i2c_hw_engine *engine) 242 { 243 dal_i2c_engine_destruct(&engine->base); 244 } 245