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 /*
27  * Pre-requisites: headers required by header of this unit
28  */
29 
30 #include "dm_services.h"
31 #include "include/gpio_interface.h"
32 #include "include/gpio_service_interface.h"
33 #include "hw_translate.h"
34 #include "hw_factory.h"
35 
36 /*
37  * Header of this unit
38  */
39 
40 #include "gpio_service.h"
41 
42 /*
43  * Post-requisites: headers required by this unit
44  */
45 
46 #include "hw_gpio.h"
47 
48 /*
49  * @brief
50  * Public API.
51  */
52 
53 struct gpio_service *dal_gpio_service_create(
54 	enum dce_version dce_version_major,
55 	enum dce_version dce_version_minor,
56 	struct dc_context *ctx)
57 {
58 	struct gpio_service *service;
59 
60 	uint32_t index_of_id;
61 
62 	service = dm_alloc(sizeof(struct gpio_service));
63 
64 	if (!service) {
65 		BREAK_TO_DEBUGGER();
66 		return NULL;
67 	}
68 
69 	if (!dal_hw_translate_init(&service->translate, dce_version_major,
70 			dce_version_minor)) {
71 		BREAK_TO_DEBUGGER();
72 		goto failure_1;
73 	}
74 
75 	if (!dal_hw_factory_init(&service->factory, dce_version_major,
76 			dce_version_minor)) {
77 		BREAK_TO_DEBUGGER();
78 		goto failure_1;
79 	}
80 
81 	/* allocate and initialize business storage */
82 	{
83 		const uint32_t bits_per_uint = sizeof(uint32_t) << 3;
84 
85 		index_of_id = 0;
86 		service->ctx = ctx;
87 
88 		do {
89 			uint32_t number_of_bits =
90 				service->factory.number_of_pins[index_of_id];
91 
92 			uint32_t number_of_uints =
93 				(number_of_bits + bits_per_uint - 1) /
94 				bits_per_uint;
95 
96 			uint32_t *slot;
97 
98 			if (number_of_bits) {
99 				uint32_t index_of_uint = 0;
100 
101 				slot = dm_alloc(number_of_uints * sizeof(uint32_t));
102 
103 				if (!slot) {
104 					BREAK_TO_DEBUGGER();
105 					goto failure_2;
106 				}
107 
108 				do {
109 					slot[index_of_uint] = 0;
110 
111 					++index_of_uint;
112 				} while (index_of_uint < number_of_uints);
113 			} else
114 				slot = NULL;
115 
116 			service->busyness[index_of_id] = slot;
117 
118 			++index_of_id;
119 		} while (index_of_id < GPIO_ID_COUNT);
120 	}
121 
122 	return service;
123 
124 failure_2:
125 	while (index_of_id) {
126 		uint32_t *slot;
127 
128 		--index_of_id;
129 
130 		slot = service->busyness[index_of_id];
131 
132 		if (slot)
133 			dm_free(slot);
134 	};
135 
136 failure_1:
137 	dm_free(service);
138 
139 	return NULL;
140 }
141 
142 struct gpio *dal_gpio_service_create_irq(
143 	struct gpio_service *service,
144 	uint32_t offset,
145 	uint32_t mask)
146 {
147 	enum gpio_id id;
148 	uint32_t en;
149 
150 	if (!service->translate.funcs->offset_to_id(offset, mask, &id, &en)) {
151 		ASSERT_CRITICAL(false);
152 		return NULL;
153 	}
154 
155 	return dal_gpio_create_irq(service, id, en);
156 }
157 
158 void dal_gpio_service_destroy(
159 	struct gpio_service **ptr)
160 {
161 	if (!ptr || !*ptr) {
162 		BREAK_TO_DEBUGGER();
163 		return;
164 	}
165 
166 	/* free business storage */
167 	{
168 		uint32_t index_of_id = 0;
169 
170 		do {
171 			uint32_t *slot = (*ptr)->busyness[index_of_id];
172 
173 			if (slot)
174 				dm_free(slot);
175 
176 			++index_of_id;
177 		} while (index_of_id < GPIO_ID_COUNT);
178 	}
179 
180 	dm_free(*ptr);
181 
182 	*ptr = NULL;
183 }
184 
185 /*
186  * @brief
187  * Private API.
188  */
189 
190 static bool is_pin_busy(
191 	const struct gpio_service *service,
192 	enum gpio_id id,
193 	uint32_t en)
194 {
195 	const uint32_t bits_per_uint = sizeof(uint32_t) << 3;
196 
197 	const uint32_t *slot = service->busyness[id] + (en / bits_per_uint);
198 
199 	return 0 != (*slot & (1 << (en % bits_per_uint)));
200 }
201 
202 static void set_pin_busy(
203 	struct gpio_service *service,
204 	enum gpio_id id,
205 	uint32_t en)
206 {
207 	const uint32_t bits_per_uint = sizeof(uint32_t) << 3;
208 
209 	service->busyness[id][en / bits_per_uint] |=
210 		(1 << (en % bits_per_uint));
211 }
212 
213 static void set_pin_free(
214 	struct gpio_service *service,
215 	enum gpio_id id,
216 	uint32_t en)
217 {
218 	const uint32_t bits_per_uint = sizeof(uint32_t) << 3;
219 
220 	service->busyness[id][en / bits_per_uint] &=
221 		~(1 << (en % bits_per_uint));
222 }
223 
224 enum gpio_result dal_gpio_service_open(
225 	struct gpio_service *service,
226 	enum gpio_id id,
227 	uint32_t en,
228 	enum gpio_mode mode,
229 	struct hw_gpio_pin **ptr)
230 {
231 	struct hw_gpio_pin *pin;
232 
233 	if (!service->busyness[id]) {
234 		ASSERT_CRITICAL(false);
235 		return GPIO_RESULT_OPEN_FAILED;
236 	}
237 
238 	if (is_pin_busy(service, id, en)) {
239 		ASSERT_CRITICAL(false);
240 		return GPIO_RESULT_DEVICE_BUSY;
241 	}
242 
243 	switch (id) {
244 	case GPIO_ID_DDC_DATA:
245 		pin = service->factory.funcs->create_ddc_data(
246 			service->ctx, id, en);
247 		service->factory.funcs->define_ddc_registers(pin, en);
248 	break;
249 	case GPIO_ID_DDC_CLOCK:
250 		pin = service->factory.funcs->create_ddc_clock(
251 			service->ctx, id, en);
252 		service->factory.funcs->define_ddc_registers(pin, en);
253 	break;
254 	case GPIO_ID_GENERIC:
255 		pin = service->factory.funcs->create_generic(
256 			service->ctx, id, en);
257 	break;
258 	case GPIO_ID_HPD:
259 		pin = service->factory.funcs->create_hpd(
260 			service->ctx, id, en);
261 		service->factory.funcs->define_hpd_registers(pin, en);
262 	break;
263 	case GPIO_ID_SYNC:
264 		pin = service->factory.funcs->create_sync(
265 			service->ctx, id, en);
266 	break;
267 	case GPIO_ID_GSL:
268 		pin = service->factory.funcs->create_gsl(
269 			service->ctx, id, en);
270 	break;
271 	default:
272 		ASSERT_CRITICAL(false);
273 		return GPIO_RESULT_NON_SPECIFIC_ERROR;
274 	}
275 
276 	if (!pin) {
277 		ASSERT_CRITICAL(false);
278 		return GPIO_RESULT_NON_SPECIFIC_ERROR;
279 	}
280 
281 	if (!pin->funcs->open(pin, mode)) {
282 		ASSERT_CRITICAL(false);
283 		dal_gpio_service_close(service, &pin);
284 		return GPIO_RESULT_OPEN_FAILED;
285 	}
286 
287 	set_pin_busy(service, id, en);
288 	*ptr = pin;
289 	return GPIO_RESULT_OK;
290 }
291 
292 void dal_gpio_service_close(
293 	struct gpio_service *service,
294 	struct hw_gpio_pin **ptr)
295 {
296 	struct hw_gpio_pin *pin;
297 
298 	if (!ptr) {
299 		ASSERT_CRITICAL(false);
300 		return;
301 	}
302 
303 	pin = *ptr;
304 
305 	if (pin) {
306 		set_pin_free(service, pin->id, pin->en);
307 
308 		pin->funcs->close(pin);
309 
310 		pin->funcs->destroy(ptr);
311 	}
312 }
313 
314 
315 enum dc_irq_source dal_irq_get_source(
316 	const struct gpio *irq)
317 {
318 	enum gpio_id id = dal_gpio_get_id(irq);
319 
320 	switch (id) {
321 	case GPIO_ID_HPD:
322 		return (enum dc_irq_source)(DC_IRQ_SOURCE_HPD1 +
323 			dal_gpio_get_enum(irq));
324 	case GPIO_ID_GPIO_PAD:
325 		return (enum dc_irq_source)(DC_IRQ_SOURCE_GPIOPAD0 +
326 			dal_gpio_get_enum(irq));
327 	default:
328 		return DC_IRQ_SOURCE_INVALID;
329 	}
330 }
331 
332 enum dc_irq_source dal_irq_get_rx_source(
333 	const struct gpio *irq)
334 {
335 	enum gpio_id id = dal_gpio_get_id(irq);
336 
337 	switch (id) {
338 	case GPIO_ID_HPD:
339 		return (enum dc_irq_source)(DC_IRQ_SOURCE_HPD1RX +
340 			dal_gpio_get_enum(irq));
341 	default:
342 		return DC_IRQ_SOURCE_INVALID;
343 	}
344 }
345 
346 enum gpio_result dal_irq_setup_hpd_filter(
347 	struct gpio *irq,
348 	struct gpio_hpd_config *config)
349 {
350 	struct gpio_config_data config_data;
351 
352 	if (!config)
353 		return GPIO_RESULT_INVALID_DATA;
354 
355 	config_data.type = GPIO_CONFIG_TYPE_HPD;
356 	config_data.config.hpd = *config;
357 
358 	return dal_gpio_set_config(irq, &config_data);
359 }
360 
361 /*
362  * @brief
363  * Creation and destruction
364  */
365 
366 struct gpio *dal_gpio_create_irq(
367 	struct gpio_service *service,
368 	enum gpio_id id,
369 	uint32_t en)
370 {
371 	struct gpio *irq;
372 
373 	switch (id) {
374 	case GPIO_ID_HPD:
375 	case GPIO_ID_GPIO_PAD:
376 	break;
377 	default:
378 		ASSERT_CRITICAL(false);
379 		return NULL;
380 	}
381 
382 	irq = dal_gpio_create(
383 		service, id, en, GPIO_PIN_OUTPUT_STATE_DEFAULT);
384 
385 	if (irq)
386 		return irq;
387 
388 	ASSERT_CRITICAL(false);
389 	return NULL;
390 }
391 
392 void dal_gpio_destroy_irq(
393 	struct gpio **irq)
394 {
395 	if (!irq || !*irq) {
396 		ASSERT_CRITICAL(false);
397 		return;
398 	}
399 
400 	dal_gpio_close(*irq);
401 	dal_gpio_destroy(irq);
402 	dm_free(*irq);
403 
404 	*irq = NULL;
405 }
406 
407 struct ddc *dal_gpio_create_ddc(
408 	struct gpio_service *service,
409 	uint32_t offset,
410 	uint32_t mask,
411 	struct gpio_ddc_hw_info *info)
412 {
413 	enum gpio_id id;
414 	uint32_t en;
415 	struct ddc *ddc;
416 
417 	if (!service->translate.funcs->offset_to_id(offset, mask, &id, &en))
418 		return NULL;
419 
420 	ddc = dm_alloc(sizeof(struct ddc));
421 
422 	if (!ddc) {
423 		BREAK_TO_DEBUGGER();
424 		return NULL;
425 	}
426 
427 	ddc->pin_data = dal_gpio_create(
428 		service, GPIO_ID_DDC_DATA, en, GPIO_PIN_OUTPUT_STATE_DEFAULT);
429 
430 	if (!ddc->pin_data) {
431 		BREAK_TO_DEBUGGER();
432 		goto failure_1;
433 	}
434 
435 	ddc->pin_clock = dal_gpio_create(
436 		service, GPIO_ID_DDC_CLOCK, en, GPIO_PIN_OUTPUT_STATE_DEFAULT);
437 
438 	if (!ddc->pin_clock) {
439 		BREAK_TO_DEBUGGER();
440 		goto failure_2;
441 	}
442 
443 	ddc->hw_info = *info;
444 
445 	ddc->ctx = service->ctx;
446 
447 	return ddc;
448 
449 failure_2:
450 	dal_gpio_destroy(&ddc->pin_data);
451 
452 failure_1:
453 	dm_free(ddc);
454 
455 	return NULL;
456 }
457 
458 void dal_gpio_destroy_ddc(
459 	struct ddc **ddc)
460 {
461 	if (!ddc || !*ddc) {
462 		BREAK_TO_DEBUGGER();
463 		return;
464 	}
465 
466 	dal_ddc_close(*ddc);
467 	dal_gpio_destroy(&(*ddc)->pin_data);
468 	dal_gpio_destroy(&(*ddc)->pin_clock);
469 	dm_free(*ddc);
470 
471 	*ddc = NULL;
472 }
473 
474 enum gpio_result dal_ddc_open(
475 	struct ddc *ddc,
476 	enum gpio_mode mode,
477 	enum gpio_ddc_config_type config_type)
478 {
479 	enum gpio_result result;
480 
481 	struct gpio_config_data config_data;
482 	struct hw_gpio *hw_data;
483 	struct hw_gpio *hw_clock;
484 
485 	result = dal_gpio_open_ex(ddc->pin_data, mode);
486 
487 	if (result != GPIO_RESULT_OK) {
488 		BREAK_TO_DEBUGGER();
489 		return result;
490 	}
491 
492 	result = dal_gpio_open_ex(ddc->pin_clock, mode);
493 
494 	if (result != GPIO_RESULT_OK) {
495 		BREAK_TO_DEBUGGER();
496 		goto failure;
497 	}
498 
499 	/* DDC clock and data pins should belong
500 	 * to the same DDC block id,
501 	 * we use the data pin to set the pad mode. */
502 
503 	if (mode == GPIO_MODE_INPUT)
504 		/* this is from detect_sink_type,
505 		 * we need extra delay there */
506 		config_data.type = GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE;
507 	else
508 		config_data.type = GPIO_CONFIG_TYPE_DDC;
509 
510 	config_data.config.ddc.type = config_type;
511 
512 	hw_data = FROM_HW_GPIO_PIN(ddc->pin_data->pin);
513 	hw_clock = FROM_HW_GPIO_PIN(ddc->pin_clock->pin);
514 
515 	config_data.config.ddc.data_en_bit_present = hw_data->store.en != 0;
516 	config_data.config.ddc.clock_en_bit_present = hw_clock->store.en != 0;
517 
518 	result = dal_gpio_set_config(ddc->pin_data, &config_data);
519 
520 	if (result == GPIO_RESULT_OK)
521 		return result;
522 
523 	BREAK_TO_DEBUGGER();
524 
525 	dal_gpio_close(ddc->pin_clock);
526 
527 failure:
528 	dal_gpio_close(ddc->pin_data);
529 
530 	return result;
531 }
532 
533 enum gpio_result dal_ddc_change_mode(
534 	struct ddc *ddc,
535 	enum gpio_mode mode)
536 {
537 	enum gpio_result result;
538 
539 	enum gpio_mode original_mode =
540 		dal_gpio_get_mode(ddc->pin_data);
541 
542 	result = dal_gpio_change_mode(ddc->pin_data, mode);
543 
544 	/* [anaumov] DAL2 code returns GPIO_RESULT_NON_SPECIFIC_ERROR
545 	 * in case of failures;
546 	 * set_mode() is so that, in case of failure,
547 	 * we must explicitly set original mode */
548 
549 	if (result != GPIO_RESULT_OK)
550 		goto failure;
551 
552 	result = dal_gpio_change_mode(ddc->pin_clock, mode);
553 
554 	if (result == GPIO_RESULT_OK)
555 		return result;
556 
557 	dal_gpio_change_mode(ddc->pin_clock, original_mode);
558 
559 failure:
560 	dal_gpio_change_mode(ddc->pin_data, original_mode);
561 
562 	return result;
563 }
564 
565 enum gpio_ddc_line dal_ddc_get_line(
566 	const struct ddc *ddc)
567 {
568 	return (enum gpio_ddc_line)dal_gpio_get_enum(ddc->pin_data);
569 }
570 
571 enum gpio_result dal_ddc_set_config(
572 	struct ddc *ddc,
573 	enum gpio_ddc_config_type config_type)
574 {
575 	struct gpio_config_data config_data;
576 
577 	config_data.type = GPIO_CONFIG_TYPE_DDC;
578 
579 	config_data.config.ddc.type = config_type;
580 	config_data.config.ddc.data_en_bit_present = false;
581 	config_data.config.ddc.clock_en_bit_present = false;
582 
583 	return dal_gpio_set_config(ddc->pin_data, &config_data);
584 }
585 
586 void dal_ddc_close(
587 	struct ddc *ddc)
588 {
589 	dal_gpio_close(ddc->pin_clock);
590 	dal_gpio_close(ddc->pin_data);
591 }
592 
593