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