xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/amd/display/dc/dce/amdgpu_dce_i2c_sw.c (revision 41ec02673d281bbb3d38e6c78504ce6e30c228c1)
1 /*	$NetBSD: amdgpu_dce_i2c_sw.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $	*/
2 
3 /*
4  * Copyright 2018 Advanced Micro Devices, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * Authors: AMD
25  *
26  */
27 
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: amdgpu_dce_i2c_sw.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $");
30 
31 #include <linux/delay.h>
32 
33 #include "dce_i2c.h"
34 #include "dce_i2c_sw.h"
35 #include "include/gpio_service_interface.h"
36 #define SCL false
37 #define SDA true
38 
dce_i2c_sw_construct(struct dce_i2c_sw * dce_i2c_sw,struct dc_context * ctx)39 void dce_i2c_sw_construct(
40 	struct dce_i2c_sw *dce_i2c_sw,
41 	struct dc_context *ctx)
42 {
43 	dce_i2c_sw->ctx = ctx;
44 }
45 
read_bit_from_ddc(struct ddc * ddc,bool data_nor_clock)46 static inline bool read_bit_from_ddc(
47 	struct ddc *ddc,
48 	bool data_nor_clock)
49 {
50 	uint32_t value = 0;
51 
52 	if (data_nor_clock)
53 		dal_gpio_get_value(ddc->pin_data, &value);
54 	else
55 		dal_gpio_get_value(ddc->pin_clock, &value);
56 
57 	return (value != 0);
58 }
59 
write_bit_to_ddc(struct ddc * ddc,bool data_nor_clock,bool bit)60 static inline void write_bit_to_ddc(
61 	struct ddc *ddc,
62 	bool data_nor_clock,
63 	bool bit)
64 {
65 	uint32_t value = bit ? 1 : 0;
66 
67 	if (data_nor_clock)
68 		dal_gpio_set_value(ddc->pin_data, value);
69 	else
70 		dal_gpio_set_value(ddc->pin_clock, value);
71 }
72 
release_engine_dce_sw(struct resource_pool * pool,struct dce_i2c_sw * dce_i2c_sw)73 static void release_engine_dce_sw(
74 	struct resource_pool *pool,
75 	struct dce_i2c_sw *dce_i2c_sw)
76 {
77 	dal_ddc_close(dce_i2c_sw->ddc);
78 	dce_i2c_sw->ddc = NULL;
79 }
80 
wait_for_scl_high_sw(struct dc_context * ctx,struct ddc * ddc,uint16_t clock_delay_div_4)81 static bool wait_for_scl_high_sw(
82 	struct dc_context *ctx,
83 	struct ddc *ddc,
84 	uint16_t clock_delay_div_4)
85 {
86 	uint32_t scl_retry = 0;
87 	uint32_t scl_retry_max = I2C_SW_TIMEOUT_DELAY / clock_delay_div_4;
88 
89 	udelay(clock_delay_div_4);
90 
91 	do {
92 		if (read_bit_from_ddc(ddc, SCL))
93 			return true;
94 
95 		udelay(clock_delay_div_4);
96 
97 		++scl_retry;
98 	} while (scl_retry <= scl_retry_max);
99 
100 	return false;
101 }
write_byte_sw(struct dc_context * ctx,struct ddc * ddc_handle,uint16_t clock_delay_div_4,uint8_t byte)102 static bool write_byte_sw(
103 	struct dc_context *ctx,
104 	struct ddc *ddc_handle,
105 	uint16_t clock_delay_div_4,
106 	uint8_t byte)
107 {
108 	int32_t shift = 7;
109 	bool ack;
110 
111 	/* bits are transmitted serially, starting from MSB */
112 
113 	do {
114 		udelay(clock_delay_div_4);
115 
116 		write_bit_to_ddc(ddc_handle, SDA, (byte >> shift) & 1);
117 
118 		udelay(clock_delay_div_4);
119 
120 		write_bit_to_ddc(ddc_handle, SCL, true);
121 
122 		if (!wait_for_scl_high_sw(ctx, ddc_handle, clock_delay_div_4))
123 			return false;
124 
125 		write_bit_to_ddc(ddc_handle, SCL, false);
126 
127 		--shift;
128 	} while (shift >= 0);
129 
130 	/* The display sends ACK by preventing the SDA from going high
131 	 * after the SCL pulse we use to send our last data bit.
132 	 * If the SDA goes high after that bit, it's a NACK
133 	 */
134 
135 	udelay(clock_delay_div_4);
136 
137 	write_bit_to_ddc(ddc_handle, SDA, true);
138 
139 	udelay(clock_delay_div_4);
140 
141 	write_bit_to_ddc(ddc_handle, SCL, true);
142 
143 	if (!wait_for_scl_high_sw(ctx, ddc_handle, clock_delay_div_4))
144 		return false;
145 
146 	/* read ACK bit */
147 
148 	ack = !read_bit_from_ddc(ddc_handle, SDA);
149 
150 	udelay(clock_delay_div_4 << 1);
151 
152 	write_bit_to_ddc(ddc_handle, SCL, false);
153 
154 	udelay(clock_delay_div_4 << 1);
155 
156 	return ack;
157 }
158 
read_byte_sw(struct dc_context * ctx,struct ddc * ddc_handle,uint16_t clock_delay_div_4,uint8_t * byte,bool more)159 static bool read_byte_sw(
160 	struct dc_context *ctx,
161 	struct ddc *ddc_handle,
162 	uint16_t clock_delay_div_4,
163 	uint8_t *byte,
164 	bool more)
165 {
166 	int32_t shift = 7;
167 
168 	uint8_t data = 0;
169 
170 	/* The data bits are read from MSB to LSB;
171 	 * bit is read while SCL is high
172 	 */
173 
174 	do {
175 		write_bit_to_ddc(ddc_handle, SCL, true);
176 
177 		if (!wait_for_scl_high_sw(ctx, ddc_handle, clock_delay_div_4))
178 			return false;
179 
180 		if (read_bit_from_ddc(ddc_handle, SDA))
181 			data |= (1 << shift);
182 
183 		write_bit_to_ddc(ddc_handle, SCL, false);
184 
185 		udelay(clock_delay_div_4 << 1);
186 
187 		--shift;
188 	} while (shift >= 0);
189 
190 	/* read only whole byte */
191 
192 	*byte = data;
193 
194 	udelay(clock_delay_div_4);
195 
196 	/* send the acknowledge bit:
197 	 * SDA low means ACK, SDA high means NACK
198 	 */
199 
200 	write_bit_to_ddc(ddc_handle, SDA, !more);
201 
202 	udelay(clock_delay_div_4);
203 
204 	write_bit_to_ddc(ddc_handle, SCL, true);
205 
206 	if (!wait_for_scl_high_sw(ctx, ddc_handle, clock_delay_div_4))
207 		return false;
208 
209 	write_bit_to_ddc(ddc_handle, SCL, false);
210 
211 	udelay(clock_delay_div_4);
212 
213 	write_bit_to_ddc(ddc_handle, SDA, true);
214 
215 	udelay(clock_delay_div_4);
216 
217 	return true;
218 }
stop_sync_sw(struct dc_context * ctx,struct ddc * ddc_handle,uint16_t clock_delay_div_4)219 static bool stop_sync_sw(
220 	struct dc_context *ctx,
221 	struct ddc *ddc_handle,
222 	uint16_t clock_delay_div_4)
223 {
224 	uint32_t retry = 0;
225 
226 	/* The I2C communications stop signal is:
227 	 * the SDA going high from low, while the SCL is high.
228 	 */
229 
230 	write_bit_to_ddc(ddc_handle, SCL, false);
231 
232 	udelay(clock_delay_div_4);
233 
234 	write_bit_to_ddc(ddc_handle, SDA, false);
235 
236 	udelay(clock_delay_div_4);
237 
238 	write_bit_to_ddc(ddc_handle, SCL, true);
239 
240 	if (!wait_for_scl_high_sw(ctx, ddc_handle, clock_delay_div_4))
241 		return false;
242 
243 	write_bit_to_ddc(ddc_handle, SDA, true);
244 
245 	do {
246 		udelay(clock_delay_div_4);
247 
248 		if (read_bit_from_ddc(ddc_handle, SDA))
249 			return true;
250 
251 		++retry;
252 	} while (retry <= 2);
253 
254 	return false;
255 }
i2c_write_sw(struct dc_context * ctx,struct ddc * ddc_handle,uint16_t clock_delay_div_4,uint8_t address,uint32_t length,const uint8_t * data)256 static bool i2c_write_sw(
257 	struct dc_context *ctx,
258 	struct ddc *ddc_handle,
259 	uint16_t clock_delay_div_4,
260 	uint8_t address,
261 	uint32_t length,
262 	const uint8_t *data)
263 {
264 	uint32_t i = 0;
265 
266 	if (!write_byte_sw(ctx, ddc_handle, clock_delay_div_4, address))
267 		return false;
268 
269 	while (i < length) {
270 		if (!write_byte_sw(ctx, ddc_handle, clock_delay_div_4, data[i]))
271 			return false;
272 		++i;
273 	}
274 
275 	return true;
276 }
277 
i2c_read_sw(struct dc_context * ctx,struct ddc * ddc_handle,uint16_t clock_delay_div_4,uint8_t address,uint32_t length,uint8_t * data)278 static bool i2c_read_sw(
279 	struct dc_context *ctx,
280 	struct ddc *ddc_handle,
281 	uint16_t clock_delay_div_4,
282 	uint8_t address,
283 	uint32_t length,
284 	uint8_t *data)
285 {
286 	uint32_t i = 0;
287 
288 	if (!write_byte_sw(ctx, ddc_handle, clock_delay_div_4, address))
289 		return false;
290 
291 	while (i < length) {
292 		if (!read_byte_sw(ctx, ddc_handle, clock_delay_div_4, data + i,
293 			i < length - 1))
294 			return false;
295 		++i;
296 	}
297 
298 	return true;
299 }
300 
301 
302 
start_sync_sw(struct dc_context * ctx,struct ddc * ddc_handle,uint16_t clock_delay_div_4)303 static bool start_sync_sw(
304 	struct dc_context *ctx,
305 	struct ddc *ddc_handle,
306 	uint16_t clock_delay_div_4)
307 {
308 	uint32_t retry = 0;
309 
310 	/* The I2C communications start signal is:
311 	 * the SDA going low from high, while the SCL is high.
312 	 */
313 
314 	write_bit_to_ddc(ddc_handle, SCL, true);
315 
316 	udelay(clock_delay_div_4);
317 
318 	do {
319 		write_bit_to_ddc(ddc_handle, SDA, true);
320 
321 		if (!read_bit_from_ddc(ddc_handle, SDA)) {
322 			++retry;
323 			continue;
324 		}
325 
326 		udelay(clock_delay_div_4);
327 
328 		write_bit_to_ddc(ddc_handle, SCL, true);
329 
330 		if (!wait_for_scl_high_sw(ctx, ddc_handle, clock_delay_div_4))
331 			break;
332 
333 		write_bit_to_ddc(ddc_handle, SDA, false);
334 
335 		udelay(clock_delay_div_4);
336 
337 		write_bit_to_ddc(ddc_handle, SCL, false);
338 
339 		udelay(clock_delay_div_4);
340 
341 		return true;
342 	} while (retry <= I2C_SW_RETRIES);
343 
344 	return false;
345 }
346 
dce_i2c_sw_engine_set_speed(struct dce_i2c_sw * engine,uint32_t speed)347 void dce_i2c_sw_engine_set_speed(
348 	struct dce_i2c_sw *engine,
349 	uint32_t speed)
350 {
351 	ASSERT(speed);
352 
353 	engine->speed = speed ? speed : DCE_I2C_DEFAULT_I2C_SW_SPEED;
354 
355 	engine->clock_delay = 1000 / engine->speed;
356 
357 	if (engine->clock_delay < 12)
358 		engine->clock_delay = 12;
359 }
360 
dce_i2c_sw_engine_acquire_engine(struct dce_i2c_sw * engine,struct ddc * ddc)361 bool dce_i2c_sw_engine_acquire_engine(
362 	struct dce_i2c_sw *engine,
363 	struct ddc *ddc)
364 {
365 	enum gpio_result result;
366 
367 	result = dal_ddc_open(ddc, GPIO_MODE_FAST_OUTPUT,
368 		GPIO_DDC_CONFIG_TYPE_MODE_I2C);
369 
370 	if (result != GPIO_RESULT_OK)
371 		return false;
372 
373 	engine->ddc = ddc;
374 
375 	return true;
376 }
dce_i2c_engine_acquire_sw(struct dce_i2c_sw * dce_i2c_sw,struct ddc * ddc_handle)377 bool dce_i2c_engine_acquire_sw(
378 	struct dce_i2c_sw *dce_i2c_sw,
379 	struct ddc *ddc_handle)
380 {
381 	uint32_t counter = 0;
382 	bool result;
383 
384 	do {
385 
386 		result = dce_i2c_sw_engine_acquire_engine(
387 				dce_i2c_sw, ddc_handle);
388 
389 		if (result)
390 			break;
391 
392 		/* i2c_engine is busy by VBios, lets wait and retry */
393 
394 		udelay(10);
395 
396 		++counter;
397 	} while (counter < 2);
398 
399 	return result;
400 }
401 
402 
403 
404 
dce_i2c_sw_engine_submit_channel_request(struct dce_i2c_sw * engine,struct i2c_request_transaction_data * req)405 void dce_i2c_sw_engine_submit_channel_request(
406 	struct dce_i2c_sw *engine,
407 	struct i2c_request_transaction_data *req)
408 {
409 	struct ddc *ddc = engine->ddc;
410 	uint16_t clock_delay_div_4 = engine->clock_delay >> 2;
411 
412 	/* send sync (start / repeated start) */
413 
414 	bool result = start_sync_sw(engine->ctx, ddc, clock_delay_div_4);
415 
416 	/* process payload */
417 
418 	if (result) {
419 		switch (req->action) {
420 		case DCE_I2C_TRANSACTION_ACTION_I2C_WRITE:
421 		case DCE_I2C_TRANSACTION_ACTION_I2C_WRITE_MOT:
422 			result = i2c_write_sw(engine->ctx, ddc, clock_delay_div_4,
423 				req->address, req->length, req->data);
424 		break;
425 		case DCE_I2C_TRANSACTION_ACTION_I2C_READ:
426 		case DCE_I2C_TRANSACTION_ACTION_I2C_READ_MOT:
427 			result = i2c_read_sw(engine->ctx, ddc, clock_delay_div_4,
428 				req->address, req->length, req->data);
429 		break;
430 		default:
431 			result = false;
432 		break;
433 		}
434 	}
435 
436 	/* send stop if not 'mot' or operation failed */
437 
438 	if (!result ||
439 		(req->action == DCE_I2C_TRANSACTION_ACTION_I2C_WRITE) ||
440 		(req->action == DCE_I2C_TRANSACTION_ACTION_I2C_READ))
441 		if (!stop_sync_sw(engine->ctx, ddc, clock_delay_div_4))
442 			result = false;
443 
444 	req->status = result ?
445 		I2C_CHANNEL_OPERATION_SUCCEEDED :
446 		I2C_CHANNEL_OPERATION_FAILED;
447 }
dce_i2c_sw_engine_submit_payload(struct dce_i2c_sw * engine,struct i2c_payload * payload,bool middle_of_transaction)448 bool dce_i2c_sw_engine_submit_payload(
449 	struct dce_i2c_sw *engine,
450 	struct i2c_payload *payload,
451 	bool middle_of_transaction)
452 {
453 	struct i2c_request_transaction_data request;
454 
455 	if (!payload->write)
456 		request.action = middle_of_transaction ?
457 			DCE_I2C_TRANSACTION_ACTION_I2C_READ_MOT :
458 			DCE_I2C_TRANSACTION_ACTION_I2C_READ;
459 	else
460 		request.action = middle_of_transaction ?
461 			DCE_I2C_TRANSACTION_ACTION_I2C_WRITE_MOT :
462 			DCE_I2C_TRANSACTION_ACTION_I2C_WRITE;
463 
464 	request.address = (uint8_t) ((payload->address << 1) | !payload->write);
465 	request.length = payload->length;
466 	request.data = payload->data;
467 
468 	dce_i2c_sw_engine_submit_channel_request(engine, &request);
469 
470 	if ((request.status == I2C_CHANNEL_OPERATION_ENGINE_BUSY) ||
471 		(request.status == I2C_CHANNEL_OPERATION_FAILED))
472 		return false;
473 
474 	return true;
475 }
dce_i2c_submit_command_sw(struct resource_pool * pool,struct ddc * ddc,struct i2c_command * cmd,struct dce_i2c_sw * dce_i2c_sw)476 bool dce_i2c_submit_command_sw(
477 	struct resource_pool *pool,
478 	struct ddc *ddc,
479 	struct i2c_command *cmd,
480 	struct dce_i2c_sw *dce_i2c_sw)
481 {
482 	uint8_t index_of_payload = 0;
483 	bool result;
484 
485 	dce_i2c_sw_engine_set_speed(dce_i2c_sw, cmd->speed);
486 
487 	result = true;
488 
489 	while (index_of_payload < cmd->number_of_payloads) {
490 		bool mot = (index_of_payload != cmd->number_of_payloads - 1);
491 
492 		struct i2c_payload *payload = cmd->payloads + index_of_payload;
493 
494 		if (!dce_i2c_sw_engine_submit_payload(
495 			dce_i2c_sw, payload, mot)) {
496 			result = false;
497 			break;
498 		}
499 
500 		++index_of_payload;
501 	}
502 
503 	release_engine_dce_sw(pool, dce_i2c_sw);
504 
505 	return result;
506 }
507